Redux源码实现

Redux深度学习之源码实现

    • 1. Redux 核心概念及工作流程
    • 2. Redux基本功能实现
      • 2.1 基本功能:
      • 2.2 首先我们实现 `Redux` 的三个基本功能:
      • 2.3 实现步骤:
    • 3. 实现enhancer函数
      • 4. 实现applyMiddleWare函数
      • 5. 实现combineReducers函数
      • 6. 完整代码

为了更好的理解 Redux,我们这里自己实现一个简单版本的 Redux源码,实现了 Redux的基本功能如: getStatesubscribedispatchapplyMiddleWaresbindActionCreatorscombineReducers等。

1. Redux 核心概念及工作流程

Redux源码实现_第1张图片

  • Store:存储状态的容器,JavaScript对象
  • View: 视图,HTML页面
  • Actions: 对象,描述对状态进行怎样的操作
  • Reducers:函数,操作状态并返回新的状态

2. Redux基本功能实现

2.1 基本功能:

Redux源码实现_第2张图片

2.2 首先我们实现 Redux 的三个基本功能:

  • getState 获取状态
  • subscribe 订阅状态发生改变改变
  • dispatch 触发action

2.3 实现步骤:

  1. 定义唯一状态仓库;
  2. 定义获取状态的函数 getState;
  3. 定义触发action的函数 dispatch;
  4. 定义收集订阅状态发生变化需要通知的订阅者的函数 subscribe;
  5. 定义一个集合收集订阅者;
  6. dispatch函数中,当状态改变执行收集的订阅者函数;
  7. 返回创建的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.

3. 实现enhancer函数

在我们通过 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函数实现:

  1. 返回一个函数接收reducer函数及初始状态preloadState作为参数;
  2. 创建store 这里createStore只有两个参数;
  3. 接受dispatch方法;
  4. 定义一个_dispatch函数,他是对返回的store对象dispatch函数的重写
  5. 返回新的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
        }

    }
}

4. 实现applyMiddleWare函数

实现了上面的enhancer函数我们就可以进一步实现我们在开发过程中经常会用到了applyMiddleWare函数了。

中间件的工作流程:

Redux源码实现_第3张图片

我们首先创建两个中间件函数loggerthunk

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参数就是storediaptch方法。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
    }
}

5. 实现combineReducers函数

在实际开发中我们经常是给每个功能模块创建一个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
    }
}

6. 完整代码

代码地址:https://gitee.com/liannian9/fed-e-task-04-02/tree/master/code/ReduxSource

你可能感兴趣的:(Redux,javascript,reactjs)