什么是Redux ?
Redux
是 JavaScript
状态容器,提供可预测化的状态管理
Redux的工作原理

首页根据业务需求 我们创建对应 Store
、 Action
、State
Ruducer 是负责处理逻辑的函数
typealias SearchStore = Store<SearchState, SearchAction, SearchSever>
typealias Reducer<State, Action, Server> = (inout State, Action, Server) -> AnyPublisher<Action, Never>?
final class Store<State, Action, Server> : ObservableObject {
@Published var state: State
private let server: Server
private let reducer: Reducer<State, Action, Server>
private var effectCancellables: Set<AnyCancellable> = []
init(initialState: State, server: Server, reducer: @escaping Reducer<State, Action, Server>) {
self.state = initialState
self.server = server
self.reducer = reducer
}
func send(_ action: Action) {
guard let value = reducer(&state, action, server) else { return }
value
.receive(on: DispatchQueue.main)
.sink(receiveValue: send)
.store(in: &effectCancellables)
}
}
enum SearchAction {
case searchResult(series: [Brands.Series])
case search(text: String)
case cancel
}
struct SearchState {
var searchText: String = ""
var isSearching: Bool = false
var didSearch: Bool = false
var searchResult: [Brands.Series] = []
var isEmpty: Bool { return searchResult.isEmpty && isSearching && !searchText.isEmpty && didSearch }
mutating func clean() {
searchText = ""
isSearching = false
searchResult = []
didSearch = false
}
}
extension Store {
static func reducer(state: inout SearchState, action: SearchAction, server: SearchSever) -> AnyPublisher<SearchAction, Never> {
switch action {
case .searchResult(series: let series): state.searchResult = series
case .search(text: let text):
state.didSearch = true
return server.service
.searchPublisher(matching: text)
.replaceError(with: [])
.map { SearchAction.searchResult(series: $0) }
.eraseToAnyPublisher()
case .cancel: state.clean()
}
return Empty().eraseToAnyPublisher()
}
}
在SceneDelegate
注册 Store
为 environmentObject
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
// Create the SwiftUI view that provides the window contents.
let store = SearchStore(initialState: SearchState(), server: SearchSever(), reducer: SearchStore.reducer)
let contentView = ContentView().environmentObject(store)
// Use a UIHostingController as window root view controller.
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView)
self.window = window
window.makeKeyAndVisible()
}
}
在View 层我们只需要添加环境变量即可 然后关联上我们对应状态的参数
struct SearchView : View {
@EnvironmentObject var store: SearchStore
private var searchText: String { return store.state.searchText }
private var isSearching: Bool { return store.state.isSearching }
var body: some View {
HStack {
Image(systemName: "magnifyingglass")
.padding(.leading, 16)
TextField("Tap here to search", text: $store.state.searchText, onEditingChanged: { value in
if value { store.state.didSearch = false }
withAnimation { store.state.isSearching = true }
}, onCommit: {
store.send(.search(text: searchText))
})
Button(action: {
UIApplication.shared.windows.first { $0.isKeyWindow }?.endEditing(true)
withAnimation {
store.send(.cancel)
}
}) {
Image(systemName: "xmark")
.foregroundColor(.darkerGray)
.opacity(isSearching ? 1 : 0)
}
.padding(12)
}
.background(Color.lightGray)
.cornerRadius(10.0)
.padding(EdgeInsets(top: 8, leading: 16, bottom: 8, trailing: 16))
.navigationBarHidden(isSearching)
}
}
这里只是用Redux 在SwiftUI 中实现了一个简单的Demo, 欢迎大家来讨论!
网友评论