美文网首页
引入 Store

引入 Store

作者: 来金德瑞 | 来源:发表于2019-08-27 15:59 被阅读0次
    
    class Store {
    
        // 观察者,用于响应状态更新,第一个 State? 为旧状态,第二个 State 为当前状态
        typealias Observer = (State?, State) -> Void
    
        private(set) var state: State  // 当前状态
        private var _observers: [UUID: Observer]  // 所有的观察者
    
        // 初始化
        init(initailState: State) {
            self.state = initailState
            self._observers = [:]
        }
    
        // 发出事件
        func dispatch(event: State.Event) {
            let oldState = self.state
            self.state = State.reduce(self.state, event: event)
            _publish(oldState: oldState, newState: self.state)
        }
    
        // 订阅状态更新
        func subscribe(observer: @escaping Observer) -> UUID {
            let subscriptionID = UUID() //  UUID 是唯一标识符,该 id 可用于取消订阅
            _observers[subscriptionID] = observer
            observer(nil, self.state) // 订阅时,将当前状态回放给该观察者
            return subscriptionID
        }
    
        // 取消订阅
        func unsubscribe(_ subscriptionID: UUID) {
            _observers.removeValue(forKey: subscriptionID)
        }
    
        // 私有方法,通知所有的观察者,状态已经更新了
        private func _publish(oldState: State?, newState: State) {
            _observers.values.forEach { observer in
                observer(oldState, newState)
            }
        }
    }
    
    

    如何使用 Store:

    
    func useStore() {
        
         //首先下创建 Store
        let initailState = State(username: "",password: "",loading: false,data: nil,error: nil)
        
        let store = Store(initailState: initailState)
    
        // 然后,订阅程序状态,并且将这些状态录制下来
        // 以下变量 newStates 和 oldStates 用于录制状态历史
        var newStates: [State] = []
        var oldStates: [State?] = []
        
        let subscriptionID = store.subscribe { (oldState, newState) in
            newStates.append(newState)
            oldStates.append(oldState)
        }
        
        // 然后,模拟输入用户名事件和输入密码事件
        // 模拟真实事件
        store.dispatch(event: .onUpateUsername("beeth0ven"))
        store.dispatch(event: .onUpatePassword("123456"))
        
        // 取消订阅
        store.unsubscribe(subscriptionID)
        
        // 最后,比对录制的状态是否符合预期
        // 描叙预期
        let expectNewStates = [
            State(username: "",password: "",loading: false,data: nil,error: nil),
            State(username: "beeth0ven",password: "",loading: false,data: nil,error: nil),
            State(username: "beeth0ven",password: "123456",loading: false,data: nil,error: nil)
        ]
        
        let expectOldStates = [
            nil,
            State(username: "",password: "",loading: false,data: nil,error: nil),
            State(username: "beeth0ven",password: "",loading: false,data: nil,error: nil)
        ]
        
        // 比对结果
        newStates == expectNewStates // 结果:true 😎
        oldStates == expectOldStates // 结果:true 😎
    }
    

    这就是如何在测试环境里面使用 Store,那么在 App 里面如何使用 Store 呢。 一个 相对简单(并未优化) 的方法,就是将 Store 注入到对应的组件里面,这里以 ViewController 为例:

    • ViewController 可以使用 store.subscribe 方法订阅程序的状态。当状态更新时,比对新旧状态,然后刷新过时了的 UI。
    • 当用户触发某个事件时,调用 store.dispatch 方法将事件发出去,如:当用户点击登录按钮时,就调用 store.dispatch(event: .onTriggerLogin)
    • ViewControllerdeinit 方法里面注销订阅 store.unsubscribe(subsriptionID)

    总结

    本节主要介绍了 纯函数 和 附加作用,期间还演示如何用 纯函数 做状态管理的。最后还演化出了一个极简版的 Redux。希望大家可以从中获益!

    相关文章

      网友评论

          本文标题:引入 Store

          本文链接:https://www.haomeiwen.com/subject/qaveectx.html