Redux 原理和简单实现

前端开发中React + Redux 是大部分项目的标配,Redux也是我喜欢的库之一,他的源码也拜读过几遍,每次都有很多收获,尤其他的中间件设计模式,对自己封装一些库提供了思想上的指导。

Redux工作流程如下图:

 

 

 

 

代码实现

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
<script>

  function compose(middlewares) {
    // 相当于fn1(fn2(fn3(...ages)))
    // 所以中间件是从右到左执行
    return middlewares.reduce((a, b) => (...args) => a(b(...args)));
  }

  function createStore(reducers, middlewares) {
    const currentState = {};
    let dispatch = function (action) {
      Object.keys(reducers).forEach(function (key) {
        currentState[key] = reducers[key](currentState[key], action);
      })
    }

    function getState() {
      return currentState;
    }

    if (middlewares) {
      // 通过闭包,把当前的dispatch, getState传递到中间件中
      // (action, ...args) => dispatch(action, ...args) 这里需要使用函数实时获取dispatch, 可以理解为next等价
      const chain = middlewares.map(middleware => middleware((action, ...args) => dispatch(action, ...args), getState))
      // 传递dispatch标识next
      dispatch = compose(chain)(dispatch);
    }

    dispatch({type: 'INIT'});
    return {
      dispatch,
      getState
    }
  }

  // log 中间件
  function logMiddleware(dispatch, getState) {
    return function (next) {
      return function (action) {
        console.log(`当前的age: ${getState().userInfo ? getState().userInfo.age : null}, 将要更新age为:${JSON.stringify(action)}`);
        return next(action);
      }
    }
  }

  // thunk 中间件可以异步请求
  function thunkMiddleware(dispatch, getState) {
    return function (next) {
      return function (action) {
        if (typeof action === 'function') {
          return action(dispatch, getState);
        }
        return next(action);
      }
    }
  }

  const store = createStore({
    userInfo: function (prevState = {age: 1, name: 'initName'}, action) {
      switch (action.type) {
        case 'SET':
          return {...prevState, ...action.value};
        default:
          return prevState;
      }
    }
  }, [thunkMiddleware, logMiddleware]);

  console.log('init', store.getState().userInfo.name, store.getState().userInfo.age);

  store.dispatch({type: 'SET', value: {age: 18}});

  store.dispatch(function (dispatch, getState) {
    // 模拟异步请求
    setTimeout(function () {
      dispatch({type: 'SET', value: {age: getState().userInfo.age + 1}})
    }, 2000);
  });

  console.log(store.getState().userInfo.name, store.getState().userInfo.age);

  store.dispatch({type: 'SET', value: {name: 'xiaoLi'}});

  console.log(store.getState().userInfo.name, store.getState().userInfo.age);

  setTimeout(function () {
    console.log(store.getState().userInfo.name, store.getState().userInfo.age);
  }, 2000);

</script>
</body>
</html>

 

posted @ 2021-05-28 17:59  zhanglearning  阅读(161)  评论(0编辑  收藏  举报