Redux
,我们这里自己实现一个简单版本的 Redux
源码,实现了 Redux
的基本功能如: getState
、 subscribe
、 dispatch
、 applyMiddleWares
、 bindActionCreators
、 combineReducers
等。
Redux
的三个基本功能:getState
;dispatch
;subscribe
;dispatch
函数中,当状态改变执行收集的订阅者函数;store
对象;function createStore (reducer, preloadState) {
// 1.定义唯一状态仓库
const currentState = preloadState;
// 5. 定义一个收集订阅者的集合
const listeners = []
// 2. 定义获取状态函数
function getState() {
return currentState;
}
// 3. 触发action
function dispatch (action) {
currentState = reducer(currentState, action)
// 6. 状态改变 执行订阅者
listeners.forEach(listener => listener())
}
// 4. 收集订阅状态发生需要通知的订阅者
function subscribe (listener) {
listeners.push(listener)
}
// 7. 返回 创建的store对象
return {
getState,
dispatch,
subscribe
}
}
这样我们就已经实现了一个最简单的Redux
.
在我们通过 Redux
创建仓库时有时我们需要扩展仓库的功能,需要在派发action
的过程中监听日志、实现异步等等操作,这些操作其实都是通过createStore
传入的第三个参数进行实现的。
createStore
中的处理:当enhancer
存在我们就通过enhancer
函数创建store
function createStore (reducer, preloadState, enhancer) {
// reducer 类型判断
if (typeof reducer !== 'function') throw new Error('redcuer必须是函数');
if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
throw new Error('enhancer必须是函数')
}
// 当存在enhance函数就在enhance中创建store
return enhancer(createStore)(reducer, preloadState);
}
...第一阶段代码省略
}
enhancer
函数实现:
reducer
函数及初始状态preloadState
作为参数;store
这里createStore
只有两个参数;dispatch
方法;_dispatch
函数,他是对返回的store
对象dispatch
函数的重写store
对象function enhancer (createStore) {
//1. 返回一个函数接收 reducer函数及初始状态preloadState作为参数
return function (reducer, preloadState) {
// 2. 创建store 这里createStore只有两个参数 根据判断条件会创建一个store对象
var store = createStore(reducer, preloadState)
// 3. 接受dispatch方法
var dispatch = store.dispatch
// 4. 定义一个_dispatch函数,他是对返回的store对象dispatch函数的重写
function _dispatch (action) { // 这里实现了一个异步的功能
if (typeof action === 'function') {
return action(dispatch)
}
dispatch(action)
}
// 5. 返回新的store对象
return {
...store,
dispatch:_dispatch
}
}
}
实现了上面的enhancer
函数我们就可以进一步实现我们在开发过程中经常会用到了applyMiddleWare
函数了。
中间件的工作流程:
我们首先创建两个中间件函数logger
和thunk
。
logger
函数
const logger = function (store) {
return function (next) {
return function (action) {
console.log('logger')
next(action)
}
}
}
thunk
函数
const thunk = function (store) {
return function (next) {
return function (action) {
if (typeof action === 'function') {
return action(next)
}
next(action)
}
}
}
然后进行注册:
let store = createStore(reducer, preloadState, applyMiddleWare(logger, thunk))
在开发之前我们先理一下中间的流程:
中间件的执行遵循先注册先执行的规律,通过next
函数取执行下一个中间件,并且最后一个中间件会将action
派发给reducer
,我们都知道reducer
函数只会接受dispatch
函数派发的action
。因此在当前案例中thunk
中间件的next
参数就是store
的diaptch
方法。logger
中间件的next
参数就是thunk
中间件的最里层函数。
分析完成后,我们开始实现:
// middleWares 所有的中间件
function applyMiddleWare (...middleWares) {
return function (createStore) {
return function (reducer, preloadState) {
// 1. 创建store
var store = createStroe(reducer, preloadState)
// 2. 创建一个阉割版的store给中间件函数
const middleWareApis = {
dispatch:store.dispatch,
getState:store.getState
}
// 3. 创建一个变量接收中间件函数的第二层函数链
let chain = middleWares.map(middleWare => middleWare(middleWareApis))
// 4. 创建一个compose函数用于返回一个dispatch函数
let dispatch = compose(chain)(store.dispatch)
// 5. 返回重写后的store
return {
...store,
dispatch
}
}
}
}
// 对原始的dispatch函数进行重写
function compose(chain) {
return function (dispatch) {
//这个dispatch是最原始的dispatch 根据执行顺序最后执行
//因此这里我们需要根据chain中数组的顺序倒序处理
for (let i = chain.length - 1; i >= 0; i--) {
// 对dispatch进行倒序重写
// 在当前案例 chain[1] 是thunk函数的第二层函数, next就是原始dispatch,重新赋值后dispatch是thunk函数的第三层函数
// 在当前案例 chain[0] 是logger函数的第二层函数, next是thunk函数的第三层函数,重新赋值后dispatch是logger函数的第三层函数也是最后提供给外部的dispatch方法
dispatch = chain[i](dispatch)
}
return dispatch
}
}
在实际开发中我们经常是给每个功能模块创建一个reducer
函数,最后通过combineReducers
函数将他们全部合并起来
function combineReducers(reducers) {
// 1. 获取所有reducer函数对应key值
let keys = Object.keys(reducers)
// 2. 每个reducer必须是函数
for (var i = 0; i < reducerKeys.length; i++) {
var key = reducerKeys[i];
if (typeof reducers[key] !== 'function') throw new Error('reducer必须是函数');
}
return function (state, action) {
// 3. 定义返回的状态变量
var nextState = {};
//调用一个一个的小的reducer 将每一个小的reducer中返回的状态存储在一个新的大的对象中
for (var i = 0; i < keys.length; i++) {
// 4. 当前reducer key值
let key = keys[i]
// 5. 当前reducer的初始状态
let reducerState = state[key]
// 6. 当前reducer函数
let reducer = reducers[key]
nextState[key] = reducer(reducerState, action)
}
return nextState
}
}
代码地址:https://gitee.com/liannian9/fed-e-task-04-02/tree/master/code/ReduxSource