zoukankan      html  css  js  c++  java
  • 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>
  • 相关阅读:
    WPF 调用WINForm中的ColorDialog
    WPF 获取ControlTemplate 中的控件方法
    <转> 8个超棒的免费高质量图标搜索引擎
    WPF 右键菜单动画
    WPF 创建超级连接
    WPF 数据模板的切换简单事例
    WPF 关于ShowDialog后主窗体依然能响应键盘输入法的解决方案。
    <转>强制类型转换总结
    WPF 中的MessageBox返回值获取并判断
    WPF数据绑定实现自定义数据源
  • 原文地址:https://www.cnblogs.com/zhangkunweb/p/14823367.html
Copyright © 2011-2022 走看看