如何在 Redux 中发送网络请求?
在 Redux 中发送网络请求需要使用异步中间件如 redux-thunk 或 Redux Toolkit 的 createAsyncThunk 来处理异步逻辑,更新应用状态。
Redux 本身不直接处理异步逻辑(如网络请求),需要通过中间件实现发送请求的功能。以下是核心方法和流程:
-
理解需求:
在 Redux 应用中进行网络请求通常是为了从服务器获取数据并更新应用的state
,这个过程必须是异步的。 - 核心解决方案:异步中间件
Redux 遵循严格的同步数据流规则(dispatch action -> reducer -> state
)。要处理异步操作,必须使用中间件 (Middleware) 来增强store
的功能,使其可以dispatch
函数或Promise
而非仅仅普通对象。- 流行中间件选择:
redux-thunk
:最常用和基础的选择,允许action creators
返回函数(不仅仅是对象)。redux-saga
:使用生成器函数 (generators
) 管理复杂异步流和副作用,功能强大,学习曲线稍陡。redux-toolkit's
createAsyncThunk
:内置在Redux Toolkit
(官方推荐工具库) 中,抽象掉了大部分样板代码。
- 流行中间件选择:
- 使用
redux-thunk
实现(基本方法):
这是最常见和最基础的操作方式。- 步骤:
-
安装中间件:
npm install redux-thunk
-
在 store 中应用中间件:
applyMiddleware(thunk)
。import { createStore, applyMiddleware } from 'redux'; import thunk from 'redux-thunk'; import rootReducer from './reducers'; const store = createStore(rootReducer, applyMiddleware(thunk));
- 创建异步 Action Creator:
- 通常返回一个以
dispatch
和getState
为参数的函数(不是普通的action
对象)。在这个函数内部执行异步操作(fetch
,axios
等)。 - 根据异步操作(开始请求、请求成功、请求失败)的不同阶段,使用
dispatch
发出不同的普通action
对象。
// Action Types (需要事先定义,如 constants.js) const FETCH_USER_REQUEST = 'FETCH_USER_REQUEST'; const FETCH_USER_SUCCESS = 'FETCH_USER_SUCCESS'; const FETCH_USER_FAILURE = 'FETCH_USER_FAILURE'; // Action Creators (供组件实际dispatch) const fetchUserRequest = () => ({ type: FETCH_USER_REQUEST }); const fetchUserSuccess = (user) => ({ type: FETCH_USER_SUCCESS, payload: user }); const fetchUserFailure = (error) => ({ type: FETCH_USER_FAILURE, error: error }); // 异步 Action Creator (使用 redux-thunk) export const fetchUser = (userId) => { return (dispatch, getState) => { // (可选) 可以在 action creator 中使用额外的工具方法或 API 模块 (如 axios, fetchSignIn 示例所示) dispatch(fetchUserRequest()); // 指示开始请求,可以设置 state.loading = true 或类似状态 // 执行网络请求(使用 fetch 或 axios) fetch(`https://api.example.com/users/${userId}`) // API URL .then(response => { if (!response.ok) { throw Error(response.statusText); } return response.json(); }) .then(userData => { // 请求成功,dispatch SUCCESS action dispatch(fetchUserSuccess(userData)); }) .catch(error => { // 请求失败,dispatch FAILURE action dispatch(fetchUserFailure(error.message)); }); }; };
- 通常返回一个以
- 在 React 组件中 Dispatch 动作:
- 使用
react-redux
的connect
(mapDispatchToProps 的方式)在Class
组件中使用。 - 或者在函数组件中使用
useDispatch
Hook:
import React, { useEffect } from 'react'; import { useDispatch } from 'react-redux'; import { fetchUser } from './actions'; // 导入上一步创建的异步 action creator const UserComponent = ({ userId }) => { const dispatch = useDispatch(); useEffect(() => { // 组件挂载或 userId 改变时 dispatch 异步 action dispatch(fetchUser(userId)); // <-- dispatch FetchUser 操作 }, [dispatch, userId]); // ...渲染组件, 从 state 读取数据(需提前 mapStateToProps 或 useSelector) };
- 使用
- Reducer 处理同步 Action:
修改相应的 slice state 来处理如
FETCH_USER_SUCCESS
,FETCH_USER_FAILURE
等。- 初始化状态通常包含如
isLoading
,data
,error
字段。 - 根据不同类型的 action 更新状态。
- 初始化状态通常包含如
-
- 步骤:
- 使用
Redux Toolkit (RTK) - createAsyncThunk
实现(推荐方法):
Redux Toolkit
(RTK) 提供createAsyncThunk
函数生成异步action creators
,极大简化请求流程并管理常见的 loading, succcess, error 状态。- 步骤:
-
安装和创建 Slice(如果还未使用 RTK):
npm install @reduxjs/toolkit react-redux
在切片 Slice 文件中:
-
使用
createAsyncThunk
创建异步 thunk:import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'; import axios from 'axios'; // or your API util // 1. 创建异步 thunk export const fetchUser = createAsyncThunk('user/fetchUserStatus', async (userId, thunkAPI) => { try { const response = await axios.get(`https://api.example.com/users/${userId}`); // <-- API Call 在 createAsyncThunk 函数的函数体中执行 return response.data; // payload for the fulfilled action } catch (err) { return thunkAPI.rejectWithValue(err.response.data); // payload for the rejected action } });
-
在 Slice 中添加 ExtraReducers 处理异步
pending/fulfilled/rejected
状态:createAsyncThunk
会自动生成三种 Action Types(如'user/fetchUserStatus/pending'
)。extraReducers
中监听并自动更新:const userSlice = createSlice({ name: 'user', initialState: { data: null, isLoading: false, error: null }, reducers: { /* 如果有同步action,这里写 */ }, extraReducers: (builder) => { // <- 在 slice 中使用 extraReducers 构建器处理异步操作的状态变更 builder .addCase(fetchUser.pending, (state) => { state.isLoading = true; state.error = null; // 重置错误状态 }) .addCase(fetchUser.fulfilled, (state, action) => { state.isLoading = false; state.data = action.payload; // 更新数据 }) .addCase(fetchUser.rejected, (state, action) => { state.isLoading = false; state.error = action.error.message || 'An error occurred'; // 设置错误状态 }); } });
- 在组件中使用方式与
thunk
类似: 也是调用dispatch(fetchUser(userId))
。 - 优点:内置处理常见的请求 loading / success / error 生命周期状态转换模式代码较少,符合现代 Redux 开发实践。
-
- 步骤:
- 请求管理与状态命名规则:
- 按照异步处理生命周期设计不同的 action(通常命名为类似
Resource/FETCH_REQUEST
,Resource/FETCH_SUCCESS
,Resource/FETCH_FAILURE
) - State 中可以设置类似
data: {}, isLoading: false, error: null
的通用结构来跟踪处理状态和结果。 - 使用工具封装可重复使用的请求逻辑。
- 支持在 ActionCreator (使用 redux thunk) 的方法中使用服务或API模块来处理请求具体细节:
fetchSignIn(email, password).then(response => ...)
- 支持通过 redux-thunk / createAsyncThunk 函数的额外参数或返回值(rejectWithValue)获取服务响应的数据来更新状态。
- 按照异步处理生命周期设计不同的 action(通常命名为类似
总结关键点:Redux 中发送网络请求的核心是通过异步中间件如 redux-thunk
或者 Redux Toolkit
提供的 createAsyncThunk
。组件中 dispatch
相关的异步操作 Action Creator
;该操作内部执行 API
调用;然后根据响应结果再次正常 dispatch
出实际的“成功”、“失败”同步 action
更新 reducer
数据。管理异步任务必须依赖于支持派发函数的中间件增强 store。使用最新的 Redux Toolkit 极大简化了这一过程。