• Redux 和 Redux thunk 理解


    1: state 就像 model

    {
        todos: [{
            text: 'Eat food',
            completed: true
        }, {
            text: 'Exercise',
            completed: false
        }],
        visibilityFilter: 'SHOW_COMPLETED'
    }

    2: action, 普通的 javascript 对象, 用来描述发生了什么, 里面除了type 必须的, 还会其它属性值来改变 state。

    { type: 'ADD_TODO', text: 'Go to swimming pool' }
    { type: 'TOGGLE_TODO', index: 1 }
    { type: 'SET_VISIBILITY_FILTER', filter: 'SHOW_ALL' }

    3. 为了把 action 和 state 串起来, 就是 reducer, 例如下面:

    reducer 一定是对应于 action 里的 type 的值, 而做变化。

    function todos(state = [], action) {
        switch (action.type) {
            case 'ADD_TODO':
                return state.concat([{ text: action.text, completed: false }]);
            default:
                return state;
        }
    }

    Redux thunk 到底是怎么起作用的呢, 请看下面的代码:

    const store = createStore(reducer, preloadedState, applyMiddleware(thunk));
    当执行这个代码的时候, 实际执行了 applyMiddleware(thunk)(createStore)(reducer, preloadedState),
    这个会返回一个新的 store对象, 这个 store对象的dispatch 发生了变化。

    源码里首先定义原来的 store = createStore(reducer, preloadedState);
    然后 thunk 里面传递下面的对象:

    {
        getState: store.getState,
        dispatch: (action) => dispatch(action)
    }

    再传入原来的 store.dispatch(就是next),

    返回的函数就是新的 dispatch方法:

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

    所以当你执行, 下面的方法判断 action 是否是函数,
    dispatch( incrementAsync() );

    注意下面标红的 dispatch 跟 store.dispatch 一样,所以又重新执行了1遍 dispatch = compose(...chain)(store.dispatch);

    但是这个时候的 action 已经是 increment(), 不是函数了, 所以直接走到 next(action) 里面了。

    function incrementAsync(delay = 1000) {
      return dispatch => {
        setTimeout(() => {
          dispatch(increment());
        }, delay);
      };
    }

    Redux thunk 官网源码

    function createThunkMiddleware(extraArgument) {
      return ({ dispatch, getState }) => next => action => {
        if (typeof action === 'function') {
        //注意这里 dispatch 不用 next?
          return action(dispatch, getState, extraArgument);
        }
        // 注意这里 next 不用 dispatch
        return next(action);
      };
    }
    
    const thunk = createThunkMiddleware();
    thunk.withExtraArgument = createThunkMiddleware;
    
    export default thunk;

    applyMiddleware 源码如下:

    import compose from './compose' // 这货的作用其实就是 compose(f, g, h)(action) => f(g(h(action)))
    
    export default function applyMiddleware(...middlewares) {
    
      return function(createStore) {
      
        return function(reducer, preloadedState, enhancer) {
        
          // 用原 createStore 先生成一个 store,其包含 getState / dispatch / subscribe / replaceReducer 四个 API
          var store = createStore(reducer, preloadedState, enhancer)
          
          var dispatch = store.dispatch // 指向原 dispatch
          var chain = [] // 存储中间件的数组
      
          // 提供给中间件的 API(其实都是 store 的 API)
          var middlewareAPI = {
            getState: store.getState,
            // 注意这里面的 dispatch 已经变成下面的 dispatch 了
            dispatch: (action) => dispatch(action)
          }
          
          chain = middlewares.map(middleware => middleware(middlewareAPI))
          
          // 用原来的 store.dispatch 进行窜连
          dispatch = compose(...chain)(store.dispatch)
      
          return {
            ...store, // store 的 API 中保留 getState / subsribe / replaceReducer
            dispatch  // 新 dispatch 覆盖原 dispatch,往后调用 dispatch 就会触发 chain 内的中间件链式串联执行
          }
        }
      }
    }
  • 相关阅读:
    ELK日志管理
    Python笔记——break的注意事项
    linux下mysql集群的安装
    为什么还原innobackupex备份后查看到的Executed_Gtid_Set与xtrabackup_binlog_info不一致
    MySQL备份可能遇到的坑
    利用.frm、.ibd恢复数据
    如何得到Slave应用relay-log的时间
    mysql.user细节三问
    跳过复制错误——slave_skip_errors、slave_exec_mode
    跳过复制错误——sql_slave_skip_counter
  • 原文地址:https://www.cnblogs.com/zhengming2016/p/6822918.html
Copyright © 2020-2023  润新知