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 内的中间件链式串联执行
      }
    }
  }
}

 

posted @ 2017-05-07 23:47  zhengming  阅读(507)  评论(0编辑  收藏  举报