redux-thunk

将 api 请求放在组件中并不合理:

  • 如果用户不通过这个组件跳到其他组件,则会导致没有数据
  • 如果多个组件都请求相同的数据,则违反DRY原则,且项目难以维护

所以有必要将 api 请求转移到 redux store 中

Redux Thunk中间件允许action creator返回一个函数,用于推迟 action 的 dispatch 或者在特定条件下才dispatch,内部函数接受 store 的 dispatch 和 getState 作为参数

安装

安装redux-thunk

  1. yarn add redux-thunk

初始化

在初始化store时允许使用thunk

  1. import { createStore, applyMiddleware } from 'redux';
  2. import thunk from 'redux-thunk';
  3. import rootReducer from './reducers/index';
  4. // Note: this API requires redux@>=3.1.0
  5. const store = createStore(rootReducer, applyMiddleware(thunk));

初始化时可以使用withExtraArgument传入更多参数,如果有多个额外参数,可传入对象,如{api, Whatever}

  1. const store = createStore(
  2. reducer,
  3. applyMiddleware(thunk.withExtraArgument(api)),
  4. );
  5. // later
  6. function fetchUser(id) {
  7. return (dispatch, getState, api) => {
  8. // you can use api here
  9. };
  10. }

创建action creator

将 api 异步请求写到 action creator 里

  • 注意 ThunkAction 里的泛型
  • 在thunk action中可以完成一系列 dispatch 操作 ```tsx export const getProductCollectionsActionCreator = ():ThunkAction< void, RootState, unknown, RecommendProductsAction

    => { return async (dispatch, getstate) => {

    1. dispatch(fetchRecommendProductsStartActionCreator())
    2. try {
    3. const {data} = await axios.get('/api/productCollections')
    4. dispatch(fetchRecommendProductsSuccessActionCreator(data))
    5. }catch(error: any) {
    6. dispatch(fetchRecommendProductsFailActionCreator(error.message))
    7. }}

}

  1. <a name="LXdx6"></a>
  2. #### 在组件中使用
  3. 在类组件中使用
  4. ```typescript
  5. class HomePageComponent extends React.Component<PropsType> {
  6. componentDidMount(){
  7. this.props.getProductsCollection()
  8. }
  9. // ...
  10. }
  11. const mapDispatchToProps = (dispatch) => {
  12. return {
  13. getProductsCollection: () => {
  14. dispatch(getProductCollectionsActionCreator())
  15. }
  16. }
  17. }

自定义中间件

redux中间件的机制是劫持action, 进行进一步的封装, next = store.dispatch
redux中间件的公式

  1. const middleware = (store) => (next) => (action) => {}

自定义 actionlog 中间件

  1. import { Middleware } from "redux";
  2. export const actionLog: Middleware = (store) => (next) => (action) => {
  3. console.log("state 更新前", store.getState())
  4. console.log("fire action", action)
  5. next(action) // dispatch action
  6. console.log("state 更新后", store.getState())
  7. }

使用 actionLog 中间件

  1. import thunk from 'redux-thunk'
  2. import { actionLog } from './middlewares/actionLog'
  3. const store = createStore(rootReducer, applyMiddleware(thunk, actionLog))

这样,在每次dispatch 中间件的时候,都会经过中间件, 执行中间件中的逻辑