React+Express+Redux-Toolkit请求响应丢失问题求助
问题:React + Redux-Toolkit 请求被取消,响应返回undefined
技术栈
- 前端:React + Redux-Toolkit
- 后端:Express
问题现象
- Postman发起相同请求能得到200 OK和预期JSON响应
- React应用中请求已发送到后端,后端控制台能打印响应结果,但:
- React DevTools显示请求被拒绝
- 控制台打印
action.payload为undefined - 网络标签显示预飞请求200 OK,但有两个请求被取消
相关代码
组件代码(UserIssuedBooks.js)
import React, { useEffect } from 'react' import { useSelector, useDispatch } from 'react-redux' import { getIssuedBooks } from '../../features/user/userSlice' import BooksUser from './BooksUser'; import Box from '@mui/material/Box'; import Typography from '@mui/material/Typography'; const UserIssuedBooks = () => { const { userIssued, isLoading } = useSelector((state) => state.user) const dispatch = useDispatch() useEffect(() => { const promise = dispatch(getIssuedBooks()) return promise.abort() // 此处为问题根源 }, []); return ( <Box> {userIssued.length === 0 ? <Typography sx={{ textAlign: 'center' }}>You have Not Issued any Books</Typography> : userIssued.map((book, index) => <BooksUser book={book} key={index} /> )} </Box> ) } export default UserIssuedBooks
Slice处理代码(userSlice.js)
.addCase(getIssuedBooks.pending, (state) => { state.isLoading = true; }) .addCase(getIssuedBooks.fulfilled, (state, action) => { state.isLoading = false; state.isSuccess = true; state.userIssued = action.payload; console.log(action.payload) }) .addCase(getIssuedBooks.rejected, (state, action) => { state.isLoading = false; state.isError = true; state.message = action.payload; console.log(action.payload) // logs undefined })
截图说明
- 网络标签:预飞请求返回200 OK,两个实际请求被标记为取消状态
- React DevTools:请求处于
rejected状态 - Postman:请求正常返回200 OK及预期JSON数据
解决方案
问题核心在于useEffect的清理函数中错误调用了promise.abort():Redux-Toolkit的dispatch(createAsyncThunk())返回的promise本身不提供abort方法,直接调用会强制终止请求,导致后端返回响应时前端已取消接收,最终触发rejected状态且action.payload为undefined。
正确处理方式
方式1:支持请求取消(需要配合createAsyncThunk的signal)
如果需要在组件卸载时主动取消请求,需先修改createAsyncThunk的定义:
import { createAsyncThunk } from '@reduxjs/toolkit'; export const getIssuedBooks = createAsyncThunk( 'user/getIssuedBooks', async (_, { signal }) => { // 关联abort控制器与thunk的signal const abortController = new AbortController(); signal.addEventListener('abort', () => abortController.abort()); const response = await fetch('/your-api-endpoint', { signal: abortController.signal }); return response.json(); } );
再修正组件中的useEffect:
useEffect(() => { const promise = dispatch(getIssuedBooks()); return () => { // 此时调用的是createAsyncThunk返回promise的合法abort方法 promise.abort(); }; }, [dispatch]);
方式2:移除错误的abort调用(仅防止内存泄漏)
如果不需要主动取消请求,直接删除错误的清理逻辑即可:
useEffect(() => { dispatch(getIssuedBooks()); }, [dispatch]);
修改后请求将正常完成,fulfilled状态会被触发,action.payload能正确获取后端返回的数据。
内容的提问来源于stack exchange,提问作者Roshan Shetty
相关产品推荐
相关产品推荐

