Redux - 中间件
Redux - 中间件
Section titled “Redux - 中间件”默认情况下,Redux 的分发(dispatch)机制是同步的(synchronous)。当你分发一个 action 时,state 会立即被 reducer 更新。但对于从 API 获取数据这样的异步操作(asynchronous operations)怎么办?
这就是**中间件(middleware)**的作用。中间件提供了一个第三方扩展点,位于 action 被分发之后、到达 reducer 之前。它允许你拦截 action,修改它们,延迟它们,分发其他 action,或者与外部服务交互。
可以将中间件视为一个函数链,它位于 store.dispatch(action) 和你的根 reducer 之间。每个中间件都可以检查 action,执行任务,然后将 action(或一个不同的 action,或什么都不做)传递给链中的下一个中间件,最终到达 reducer。
中间件的常见用例包括:
- 处理异步操作(例如,API 调用)。
- 记录 actions 和 state 变化。
- 报告错误。
- 根据分发的 actions 进行 API 调用。
- 路由(Routing)。
Redux 提供了 applyMiddleware 函数来增强 store 的中间件功能。然而,推荐的 Redux store 设置方式是使用 Redux Toolkit 的 configureStore 函数,它简化了中间件的配置。
// 使用 Redux Toolkit(推荐)import { configureStore } from '@reduxjs/toolkit';import logger from 'redux-logger'; // 示例中间件import rootReducer from './reducers'; // 你的组合 reducer
const store = configureStore({ reducer: rootReducer, middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(logger), // 将 logger 添加到默认中间件中});
// 旧方式(用于理解)import { createStore, applyMiddleware } from 'redux';import thunk from 'redux-thunk'; // 示例中间件import rootReducer from './reducers';
const store = createStore(rootReducer, applyMiddleware(thunk, logger));configureStore 默认会自动包含一些有用的中间件,其中最重要的是 redux-thunk。你可以使用 middleware 选项来自定义中间件栈,通常会使用 getDefaultMiddleware 来包含默认的中间件以及你自定义的中间件。
一个 Redux 中间件是一个高阶函数(higher-order function),其签名(signature)为:store => next => action => { ... }。
store:提供了访问 store 的getState和dispatch方法的权限。next:一个将 action 传递给链中下一个中间件的函数,如果它是链中的最后一个,则传递给 reducer。你必须调用next(action)才能让 action 最终到达 reducer(除非你打算阻止它)。action:被分发(dispatched)的 action 对象。
让我们编写一个简单的自定义 logger 中间件:
const simpleLogger = store => next => action => { console.log('Dispatching action:', action); const result = next(action); // 将 action 传递给下一个中间件/reducer console.log('Next state:', store.getState()); return result; // 返回 next(action) 的结果};
// 与 configureStore 一起使用:const store = configureStore({ reducer: rootReducer, middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(simpleLogger),});处理异步性:Redux Thunk
Section titled “处理异步性:Redux Thunk”redux-thunk 是处理基本异步逻辑的标准中间件。它允许 action creator 返回一个函数(称为 “thunk”),而不是一个普通的 action 对象。这个函数接收 dispatch 和 getState 作为参数,允许它异步地分发 actions(例如,在 API 调用之后)。
Thunk Action Creator 示例:
// actions/userActions.jsimport { userApi } from './api'; // 假设这包含 API 调用函数
// Action 类型(通常由 createSlice 生成)const USER_FETCH_REQUEST = 'user/fetchRequest';const USER_FETCH_SUCCESS = 'user/fetchSuccess';const USER_FETCH_FAILURE = 'user/fetchFailure';
// Thunk Action Creatorexport const fetchUser = (userId) => async (dispatch, getState) => { dispatch({ type: USER_FETCH_REQUEST }); try { const user = await userApi.fetchById(userId); dispatch({ type: USER_FETCH_SUCCESS, payload: user }); } catch (error) { dispatch({ type: USER_FETCH_FAILURE, payload: error.message }); }};你会像分发常规 action 一样分发这个 thunk:store.dispatch(fetchUser(123));
使用 Redux Toolkit 的现代异步处理:createAsyncThunk
Section titled “使用 Redux Toolkit 的现代异步处理:createAsyncThunk”Redux Toolkit 提供了 createAsyncThunk 来简化标准的异步请求生命周期(pending/fulfilled/rejected)。
// features/users/usersSlice.jsimport { createSlice, createAsyncThunk } from '@reduxjs/toolkit';import { userApi } from './api';
// 由 createAsyncThunk 生成的异步 thunkexport const fetchUserById = createAsyncThunk( 'users/fetchByIdStatus', // Action 类型前缀 async (userId, thunkAPI) => { // 第一个参数是 payload creator 回调函数 const response = await userApi.fetchById(userId); return response.data; // 这将成为 'fulfilled' action 的 payload // 如果抛出错误,这将成为 'rejected' action 的 payload });
const usersSlice = createSlice({ name: 'users', initialState: { entity: null, loading: 'idle', error: null }, reducers: {}, extraReducers: (builder) => { builder .addCase(fetchUserById.pending, (state) => { state.loading = 'pending'; state.entity = null; state.error = null; }) .addCase(fetchUserById.fulfilled, (state, action) => { state.loading = 'succeeded'; state.entity = action.payload; // 来自异步函数的 Payload }) .addCase(fetchUserById.rejected, (state, action) => { state.loading = 'failed'; state.error = action.error.message; // 来自异步函数的 Error }); },});
export default usersSlice.reducer;
// 分发:// store.dispatch(fetchUserById(123));createAsyncThunk 会自动分发 pending/fulfilled/rejected actions,你可以在 slice 的 extraReducers 中处理它们。
其他中间件选项
Section titled “其他中间件选项”对于更复杂的异步流程或管理副作用,还有其他中间件可用,如 redux-saga(使用生成器函数)或 redux-observable(使用 RxJS Observables),但 redux-thunk(特别是通过 createAsyncThunk)对于大多数常见用例已经足够了。