redux-thunk

157 阅读3分钟

redux-thunk 是一个用于 Redux 的中间件(middleware)库,它可以让你在 Redux 中编写异步的 action creator。

在传统的 Redux 中,action creator 是一个简单的函数,用于创建一个 action 对象,并通过 dispatch 函数将该 action 对象发送给 Redux store。例如:

const fetchData = () => ({
  type: 'FETCH_DATA',
});

然而,在实际开发中,有很多场景需要进行异步操作,例如发送网络请求获取数据。传统的 action creator 并不能直接处理异步操作,因为它只能返回一个简单的 action 对象。

这就是 redux-thunk 的作用。它允许你在 action creator 中返回一个函数而不是一个 action 对象。这个函数可以接收 dispatchgetState 作为参数,并可以在函数体内执行异步操作,最终再手动调用 dispatch 函数来发送真正的 action 对象。

import { createStore, applyMiddleware } from 'redux';
import thunkMiddleware from 'redux-thunk';
import rootReducer from './reducers';

// 应用 redux-thunk 中间件
const store = createStore(rootReducer, applyMiddleware(thunkMiddleware));

// 异步 action creator
const fetchData = () => {
  return (dispatch, getState) => {
    // 可以在这里执行异步操作,例如发送网络请求获取数据
    dispatch({ type: 'FETCH_DATA_REQUEST' });

    fetch('https://api.example.com/data')
      .then(response => response.json())
      .then(data => {
        dispatch({ type: 'FETCH_DATA_SUCCESS', payload: data });
      })
      .catch(error => {
        dispatch({ type: 'FETCH_DATA_FAILURE', payload: error.message });
      });
  };
};

// 调用异步 action creator
store.dispatch(fetchData());

在上面的示例中,我们通过 applyMiddlewareredux-thunk 中间件应用到 Redux store 中。然后,我们定义了一个异步 action creator fetchData,它返回一个函数而不是一个 action 对象。在函数体内,我们可以执行异步操作,并根据操作的结果手动调用 dispatch 函数来发送不同的 action 对象,从而实现了异步操作的处理。

总结一下,redux-thunk 允许我们在 Redux 中编写异步操作,使得 action creator 可以返回一个函数,从而处理复杂的异步场景。

源码

function createThunkMiddleware<
  State = any,
  BasicAction extends Action = AnyAction,
  ExtraThunkArg = undefined
>(extraArgument?: ExtraThunkArg) {
  // Standard Redux middleware definition pattern:
  // See: https://redux.js.org/tutorials/fundamentals/part-4-store#writing-custom-middleware
  const middleware: ThunkMiddleware<State, BasicAction, ExtraThunkArg> =
    ({ dispatch, getState }) =>
    next =>
    action => {
      // The thunk middleware looks for any functions that were passed to `store.dispatch`.
      // If this "action" is really a function, call it and return the result.
      if (typeof action === 'function') {
        // Inject the store's `dispatch` and `getState` methods, as well as any "extra arg"
        return action(dispatch, getState, extraArgument)
      }

      // Otherwise, pass the action down the middleware chain as usual
      return next(action)
    }
  return middleware
}

export const thunk = createThunkMiddleware()

关键代码

if (typeof action === 'function') {
    // Inject the store's `dispatch` and `getState` methods, as well as any "extra arg"
    return action(dispatch, getState, extraArgument)
}

在这段代码中,action(dispatch, getState, extraArgument) 是一个处理异步 action 的关键步骤。这里 action 是通过 store.dispatch 派发的 action,如果它是一个函数(也就是一个 thunk action),那么中间件会将其执行,并且将 dispatchgetState 以及可能的额外参数 extraArgument 传递给这个函数。

在这段代码中,action(dispatch, getState, extraArgument) 是一个处理异步 action 的关键步骤。这里 action 是通过 store.dispatch 派发的 action,如果它是一个函数(也就是一个 thunk action),那么中间件会将其执行,并且将 dispatchgetState 以及可能的额外参数 extraArgument 传递给这个函数。

具体地说:

  1. dispatch 是 Redux store 的 dispatch 方法,它用于派发 action。
  2. getState 是 Redux store 的 getState 方法,它用于获取当前的 state。
  3. extraArgument 是可选的额外参数,可以在创建 thunkMiddleware 时传入,用于在 thunk action 中传递一些额外的数据。

当中间件检测到 action 是一个函数(thunk action)时,它会调用这个函数,并将上述参数传递给它。通常情况下,这个函数会包含异步的逻辑,例如异步请求数据或者进行一些延时操作。在函数执行完成后,它可能会返回一个对象(普通 action)或者什么都不返回(异步 action)。如果返回一个对象,这个对象会被传递给下一个中间件或者最终的 reducer 处理;如果没有返回任何内容,那么中间件链将会终止,不再向下传递这个 action,也就是说异步操作完成后不会再有其他 action 发生。