【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]