redux-thunk
将 api 请求放在组件中并不合理:
- 如果用户不通过这个组件跳到其他组件,则会导致没有数据
- 如果多个组件都请求相同的数据,则违反DRY原则,且项目难以维护
所以有必要将 api 请求转移到 redux store 中
Redux Thunk中间件允许action creator返回一个函数,用于推迟 action 的 dispatch 或者在特定条件下才dispatch,内部函数接受 store 的 dispatch 和 getState 作为参数
安装
安装redux-thunk
yarn add redux-thunk
初始化
在初始化store时允许使用thunk
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers/index';
// Note: this API requires redux@>=3.1.0
const store = createStore(rootReducer, applyMiddleware(thunk));
初始化时可以使用withExtraArgument传入更多参数,如果有多个额外参数,可传入对象,如{api, Whatever}
const store = createStore(
reducer,
applyMiddleware(thunk.withExtraArgument(api)),
);
// later
function fetchUser(id) {
return (dispatch, getState, api) => {
// you can use api here
};
}
创建action creator
将 api 异步请求写到 action creator 里
- 注意 ThunkAction 里的泛型
- 在thunk action中可以完成一系列 dispatch 操作
```tsx
export const getProductCollectionsActionCreator = ():ThunkAction<
void,
RootState,
unknown,
RecommendProductsAction
=> { return async (dispatch, getstate) => {
dispatch(fetchRecommendProductsStartActionCreator())
try {
const {data} = await axios.get('/api/productCollections')
dispatch(fetchRecommendProductsSuccessActionCreator(data))
}catch(error: any) {
dispatch(fetchRecommendProductsFailActionCreator(error.message))
}}
}
<a name="LXdx6"></a>
#### 在组件中使用
在类组件中使用
```typescript
class HomePageComponent extends React.Component<PropsType> {
componentDidMount(){
this.props.getProductsCollection()
}
// ...
}
const mapDispatchToProps = (dispatch) => {
return {
getProductsCollection: () => {
dispatch(getProductCollectionsActionCreator())
}
}
}
自定义中间件
redux中间件的机制是劫持action, 进行进一步的封装, next = store.dispatch
redux中间件的公式
const middleware = (store) => (next) => (action) => {}
自定义 actionlog 中间件
import { Middleware } from "redux";
export const actionLog: Middleware = (store) => (next) => (action) => {
console.log("state 更新前", store.getState())
console.log("fire action", action)
next(action) // dispatch action
console.log("state 更新后", store.getState())
}
使用 actionLog 中间件
import thunk from 'redux-thunk'
import { actionLog } from './middlewares/actionLog'
const store = createStore(rootReducer, applyMiddleware(thunk, actionLog))
这样,在每次dispatch 中间件的时候,都会经过中间件, 执行中间件中的逻辑