redux的原理及简单实现

…衆ロ難τιáo~ 提交于 2019-12-10 13:35:53

1、redux

抛开react,如果只是仅仅使用redux,就像如下示例:

const initialState = {
    name: 'Jack',
    age: 27,
    gender: 'boy'
};

function reducer(state = initialState, action) {
    switch(action.type) {
        case 'add':
            return { ...state, age: state.age + 1 };
        default:
            return state;
    }
}
const store = createStore(reducer);
store.subscribe(function() {
    console.log(store.getState());
});
store.dispatch({ type: 'add' });

这里其实就是一个createStore函数,返回了dispatch、subscribe、getState这三个方法,如下就是redux的简单实现:

function createStore(reducer, enhancer) {
    // createStore(reducer, applyMiddleware(thunk));
    if (enhancer) {
        return enhancer(createStore)(reducer);
    }
    let state;
    let listeners = [];
    function subscribe(fn) {
        fn && listeners.push(fn);
    }
    function dispatch(action) {
        state = reducer(state, action);
        listeners.forEach(lis => lis());
        return action;
    }
    function getState() {
        return state;
    }
    // 用于初始化state,其中type任意名称
    dispatch({ type: '@Init_XXX_dXXxx' });
    return {
        subscribe,
        dispatch,
        getState
    };
}

2、redux实现异步action

正常要想实现异步action,需要引入thunk,如:

import thunk from 'redux-thunk';
import { createStore, applyMiddleware } from 'redux';
import reducers from './reducer';

const store = createStore(reducers, applyMiddleware(thunk));

其中通过applyMiddleware来合并各种thunk。先让我们来看看一个thunk的基本结构:

const thunk = ({ getState, dispatch }) => next => action => {
    if (typeof action === 'function') {
        return action(dispatch, getState);
    }
    return next(action);
};
export default thunk;

这是一个三层嵌套函数,通过next串联各个thunk。

让我们再来看看applyMiddleware的实现:

function applyMiddleware(...middlewares) {
    return (createStore) => (...args) => {
        const store = createStore(...args);
        let dispatch = store.dispatch;
        const midApi = {
            getState: store.getState,
            // 这里保证dispatch是下面compose后,最终生成的dispatch
            dispatch: (...args) => dispatch(...args)
        };
        let midwaresChain = middlewares.map(mw => mw(midApi));
        dispatch = compose(...midwaresChain)(store.dispatch);
        return {
            ...store,
            dispatch
        };
    };
}

// fn1(fn2(fn3(...args)))
function compose(...middlewares) {
    if (!middlewares) {
        return arg => arg
    }
    return middlewares.reduce((ret, func) => {
        return (...args) => ret(func(...args))
    });
}

首先对每个thunk传入midApi进行调用,这里midApi对应thunk的第一个参数({ getState, dispatch }),最后形成的数组里的每项都各自对getState和dispatch形成一个闭包。注意:这里的dispatch就是最终compose完成后的dispatch

let midwaresChain = middlewares.map(mw => mw(midApi));

然后对midwaresChain调用compose函数,最后返回的函数为类似这种结构:fn1(fn2(fn3(...args))),然后后再传入store.dispatch调用它。这里store.dispatch对应thunk的第二个参数next,此时每个thunk返回的内容为如下函数。

根据fn1(fn2(fn3(...args)))这个调用顺序,及最后一个fn3这个thunk返回的函数会作为前一个fn2的next入参。

这样调用完成后,会最终返回一个如下函数:

action => {
    if (xxx) {
        dispatch(xxx);
        return;
    }
    // 这里的next就是后一个thunk返回的action => {}这个函数
    return next(action);
};

到此,给redux加入thunk已经实现,这里的thunk可以具备各种功能,如异步thunk:

const thunk = ({ getState, dispatch }) => next => action => {
    if (typeof action === 'function') {
        return action(dispatch, getState);
    }
    return next(action);
};

然后只需要在页面调用时传入thunk:

const store = createStore(reducer, applyMiddleware(thunk));

这片文章暂时先聊到这,后续更新react-redux的实现原理

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!