You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 16:13:35