redux-thunk思考

251 阅读1分钟

先贴源码,理解一下thunk的走向

// redux-thunk core code

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

    return next(action);
  };
}

const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;

export default thunk;
// redux src/compose.ts core code

export default function compose(...funcs: Function[]) {
  if (funcs.length === 0) {
    // infer the argument type so it is usable in inference down the line
    return <T>(arg: T) => arg
  }

  if (funcs.length === 1) {
    return funcs[0]
  }

  return funcs.reduce((a, b) => (...args: any) => a(b(...args)))
}
// redux src/applyMiddleware.ts core code

export default function applyMiddleware(
  ...middlewares: Middleware[]
): StoreEnhancer<any> {
  return (createStore: StoreCreator) => <S, A extends AnyAction>(
    reducer: Reducer<S, A>,
    ...args: any[]
  ) => {
    const store = createStore(reducer, ...args)
    let dispatch: Dispatch = () => {
      throw new Error(
        'Dispatching while constructing your middleware is not allowed. ' +
          'Other middleware would not be applied to this dispatch.'
      )
    }

    const middlewareAPI: MiddlewareAPI = {
      getState: store.getState,
      dispatch: (action, ...args) => dispatch(action, ...args)
    }
    const chain = middlewares.map(middleware => middleware(middlewareAPI))
    dispatch = compose<typeof dispatch>(...chain)(store.dispatch)

    return {
      ...store,
      dispatch
    }
  }
}

结合redux的源码可以看出dispatch会先经过thunk,thunk判别action是函数,则先同步调用函数,并且返回函数值。action可以作为一个函数被接收,那么就可以是generator函数,async函数等,尽可以在这个函数中做异步操作。

其中疑惑的是为什么形如:

// ...省略一些引入代码,看下关键代码

function fetchPosts() {
  return (dispatch) => {
    dispatch(requestPosts());
    return fetch(`http://www.reddit.com/r/reactjs.json`)
      .then(response => response.json())
      .then(json => dispatch(receivePosts(json)));
  };
}

dispatch(fetchPosts()).then((res) => { console.log(res) })

dispatch还可以接收promise继续.then,因为我起初认为action最终是要生成一个符合期望的对象传给store.dispatch,但后来仔细分析之后发现,thunk的dispatch接收一个function,最终是以这个function的返回值作为dispatch结束后的值,所以上例才能接收一个promise

这样下来,算是把thunk的来龙去脉理清了。