【react】Redux的计划思想与工作原理

打印 上一主题 下一主题

主题 783|帖子 783|积分 2349

Redux 的计划理念

Redux 的计划采用了 Facebook 提出的 Flux 数据处置惩罚理念
在 Flux 中通过建立一个公共集中数据仓库 Store 举行管理,整体分成四个部门即: View (视图层)、Action (动作)、Dispatcher (派发器)、Store (数据层)
如下图所示,当我们想要修改仓库的数据时,需要从 View 中触发 Action,由 Dispatcher 派发到 Store 修改数据,从而驱动视图更新

这种计划的利益在于其数据流向是单一的,数据的修改一定是会经过 Action、Dispatcher 等动作才华实现,方便猜测、维护状态的流向。
当我们相识了 Flux 的计划理念后,便可以照葫芦画瓢了。
如下图所示,在 Redux 中同样需要维护一个公共数据仓库 Store, 而数据流向只能通过 View 触发 Action、 Reducer更新派发, Store 改变从而驱动视图更新


工作原理

当我们相识了 Redux 的计划理念后,趁热打铁炫一波 Redux 的工作原理,我们知道使用 Redux 举行状态管理的第一步就是需要先创建数据仓库 Store, 也就会需要调用 createStore 方法。那我们就先拿 createStore 开炫。
createStore

从 Redux 源码中我们不难看出,createStore 接收 reducer初始化state中间件三个参数,当执行 createStore 时会记录当前的 state 状态,并返回 store 对象,包罗 dispatch、subscribe、getState 等属性。
此中


  • dispatch: 用来触发 Action
  • subscribe: 当 store 值的改变将触发 subscribe 的回调
  • getState: 用来获取当前的 state 状态。
getState 比力简朴,直接返回当前的 state 状态,接下来我们将着重相识 dispatch 与 subscribe 的实现。
  1. function createStore(reducer, preloadedState, enhancer) {
  2.    let currentReducer = reducer // 记录当前的 reducer
  3.    let currentState = preloadedState // 记录当前的 state
  4.    let isDispatching = false // 是否正在进行 dispatch
  5.   
  6.    function getState() {
  7.       return currentState // 通过 getState 获取当前的 state
  8.    }
  9.   
  10.    // 触发 action
  11.    function dispatch(action: A) {}
  12.   
  13.    function subscribe(listener: () => void) {}
  14.    // 初始化 state
  15.    dispatch({ type: ActionTypes.INIT } as A)
  16.   
  17.    // 返回一个 sttore
  18.    const store = {
  19.     dispatch: dispatch as Dispatch<A>,
  20.     subscribe,
  21.     getState
  22.    }
  23.    return store
  24. }
复制代码
dispatch

在 Redux 中, 修改数据的唯一方式就是通过 dispatch,而 dispatch 接受一个 action 对象作为参数,执行 dispatch 方法,将生成新的 state,并触发监听事件。
  1. function dispatch(action) {
  2.     // 如果已经在触发中,则不允许再次出发 dispatch (禁止套娃)
  3.     // 例如:在 reducer 中触发 dispatch
  4.     if (isDispatching) {
  5.       throw new Error('Reducers may not dispatch actions.')
  6.     }
  7.     try {
  8.       // 上锁
  9.       isDispatching = true
  10.       // 调用 reducer,获取新的 state
  11.       currentState = currentReducer(currentState, action)
  12.     } finally {
  13.       isDispatching = false
  14.     }
  15.     // 触发订阅事件
  16.     const listeners = (currentListeners = nextListeners)
  17.     listeners.forEach(listener => {
  18.       listener()
  19.     })
  20.     return action
  21.   }
复制代码
subscribe

在 Redux 中, 可以通过 subscribe 方法来订阅 store 的厘革, 一旦 store 发生了厘革, 就会执行订阅的回调函数
可以看到 subscribe 方法接收一个回调函数作为参数, 执行 subscribe 方法将会返回一个 unsubscribe 函数, 用于取消订阅
  1. function subscribe(listener: () => void) {
  2.     if (isDispatching) {
  3.       throw new Error()
  4.     }
  5.     let isSubscribed = true // 防止调用多次 unsubscribe
  6.     ensureCanMutateNextListeners() // 确保 nextListeners 是 currentListeners 的快照,而不是同一个引用
  7.     const listenerId = listenerIdCounter++
  8.     nextListeners.set(listenerId, listener) //nextListeners 添加订阅事件
  9.     // 取消订阅事件
  10.     return function unsubscribe() {
  11.       if (!isSubscribed) {
  12.         return
  13.       }
  14.       if (isDispatching) {
  15.         throw new Error()
  16.       }
  17.       isSubscribed = false
  18.       ensureCanMutateNextListeners(); // 如果某个订阅事件执行了 unsubscribe, nextListeners 创建了新的内存地址,而原先的listeners 依然保持不变 (dispatch 方法中的312 行)
  19.       nextListeners.delete(listenerId)
  20.       currentListeners = null
  21.     }
  22.   }
复制代码
ensureCanMutateNextListeners 与 currentListeners 的作用

承接上文,在 subscribe 中不管是注册监听还是取消监听都会调用 ensureCanMutateNextListeners 的方法,那么这个方法是做什么的呢?
从函数的逻辑上不难过出答案:
ensureCanMutateNextListeners 确保 nextListeners 是 currentListeners 的快照,而不是同一个引用
  1. function ensureCanMutateNextListeners() {
  2.     if (nextListeners === currentListeners) { // currentListeners 用来确保循环的稳定性
  3.       nextListeners = new Map()
  4.       currentListeners.forEach((listener, key) => {
  5.         nextListeners.set(key, listener)
  6.       })
  7.     }
  8. }
复制代码
在 dispatch 或者 subscribe 函数中,都是通过 nextListeners 触发监听,那为何还需要使用 currentListeners?
这里就不卖关子了,这里的 currentListeners 用于确保在 dispatch 中 listener 的数目不会发生厘革, 确保当前循环的稳固性。
请看下面的例子
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

祗疼妳一个

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表