祗疼妳一个 发表于 2025-1-5 14:42:24

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

Redux 的计划理念

Redux 的计划采用了 Facebook 提出的 Flux 数据处置惩罚理念
在 Flux 中通过建立一个公共集中数据仓库 Store 举行管理,整体分成四个部门即: View (视图层)、Action (动作)、Dispatcher (派发器)、Store (数据层)
如下图所示,当我们想要修改仓库的数据时,需要从 View 中触发 Action,由 Dispatcher 派发到 Store 修改数据,从而驱动视图更新
https://i-blog.csdnimg.cn/direct/9b49b95f44d64f929933e3562029040c.png
这种计划的利益在于其数据流向是单一的,数据的修改一定是会经过 Action、Dispatcher 等动作才华实现,方便猜测、维护状态的流向。
当我们相识了 Flux 的计划理念后,便可以照葫芦画瓢了。
如下图所示,在 Redux 中同样需要维护一个公共数据仓库 Store, 而数据流向只能通过 View 触发 Action、 Reducer更新派发, Store 改变从而驱动视图更新
https://i-blog.csdnimg.cn/direct/eef7b4fdd67b4beda8364f2f7406bc78.png

工作原理

当我们相识了 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 的实现。
function createStore(reducer, preloadedState, enhancer) {
   let currentReducer = reducer // 记录当前的 reducer
   let currentState = preloadedState // 记录当前的 state
   let isDispatching = false // 是否正在进行 dispatch

   function getState() {
      return currentState // 通过 getState 获取当前的 state
   }

   // 触发 action
   function dispatch(action: A) {}

   function subscribe(listener: () => void) {}

   // 初始化 state
   dispatch({ type: ActionTypes.INIT } as A)

   // 返回一个 sttore
   const store = {
    dispatch: dispatch as Dispatch<A>,
    subscribe,
    getState
   }
   return store
}

dispatch

在 Redux 中, 修改数据的唯一方式就是通过 dispatch,而 dispatch 接受一个 action 对象作为参数,执行 dispatch 方法,将生成新的 state,并触发监听事件。
function dispatch(action) {
    // 如果已经在触发中,则不允许再次出发 dispatch (禁止套娃)
    // 例如:在 reducer 中触发 dispatch
    if (isDispatching) {
      throw new Error('Reducers may not dispatch actions.')
    }

    try {
      // 上锁
      isDispatching = true
      // 调用 reducer,获取新的 state
      currentState = currentReducer(currentState, action)
    } finally {
      isDispatching = false
    }

    // 触发订阅事件
    const listeners = (currentListeners = nextListeners)
    listeners.forEach(listener => {
      listener()
    })
    return action
}
subscribe

在 Redux 中, 可以通过 subscribe 方法来订阅 store 的厘革, 一旦 store 发生了厘革, 就会执行订阅的回调函数
可以看到 subscribe 方法接收一个回调函数作为参数, 执行 subscribe 方法将会返回一个 unsubscribe 函数, 用于取消订阅

function subscribe(listener: () => void) {
    if (isDispatching) {
      throw new Error()
    }

    let isSubscribed = true // 防止调用多次 unsubscribe

    ensureCanMutateNextListeners() // 确保 nextListeners 是 currentListeners 的快照,而不是同一个引用
    const listenerId = listenerIdCounter++
    nextListeners.set(listenerId, listener) //nextListeners 添加订阅事件
    // 取消订阅事件
    return function unsubscribe() {
      if (!isSubscribed) {
      return
      }

      if (isDispatching) {
      throw new Error()
      }

      isSubscribed = false

      ensureCanMutateNextListeners(); // 如果某个订阅事件执行了 unsubscribe, nextListeners 创建了新的内存地址,而原先的listeners 依然保持不变 (dispatch 方法中的312 行)
      nextListeners.delete(listenerId)
      currentListeners = null
    }
}

ensureCanMutateNextListeners 与 currentListeners 的作用

承接上文,在 subscribe 中不管是注册监听还是取消监听都会调用 ensureCanMutateNextListeners 的方法,那么这个方法是做什么的呢?
从函数的逻辑上不难过出答案:
ensureCanMutateNextListeners 确保 nextListeners 是 currentListeners 的快照,而不是同一个引用
function ensureCanMutateNextListeners() {
    if (nextListeners === currentListeners) { // currentListeners 用来确保循环的稳定性
      nextListeners = new Map()
      currentListeners.forEach((listener, key) => {
      nextListeners.set(key, listener)
      })
    }
}
在 dispatch 或者 subscribe 函数中,都是通过 nextListeners 触发监听,那为何还需要使用 currentListeners?
这里就不卖关子了,这里的 currentListeners 用于确保在 dispatch 中 listener 的数目不会发生厘革, 确保当前循环的稳固性。
请看下面的例子
页: [1]
查看完整版本: 【react】Redux的计划思想与工作原理