React函数组件报错:无法在已卸载组件上更新状态
React组件内存泄漏问题修复
错误提示
Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
中文翻译:无法在已卸载的组件上执行React状态更新。这是无效操作,但表明你的应用存在内存泄漏。修复方法:在useEffect的清理函数中取消所有订阅和异步任务。
问题成因
组件的useEffect中发起了异步fetch请求,但未处理组件卸载后的状态更新逻辑。如果请求尚未完成时组件被卸载(比如用户快速跳转页面),请求返回后setData会尝试更新已卸载组件的状态,触发警告并造成内存泄漏。
修复方案
通过AbortController取消未完成的异步请求,同时优化代码细节:
import { useEffect, useState } from "react"; import Carousel from "react-elastic-carousel"; export default function Latest() { const [data, setData] = useState([]); useEffect(() => { // 创建AbortController用于取消请求 const abortController = new AbortController(); const signal = abortController.signal; fetch("https://test.emkanfinances.net/api/package/show", { signal }) .then((res) => res.json()) .then((dataRes) => setData(dataRes)) .catch((err) => { // 仅处理非取消类错误 if (err.name !== "AbortError") { console.error("数据请求失败:", err); } }); // 组件卸载时取消请求 return () => abortController.abort(); }, []); const breakPoints = [ { width: 1, itemsToShow: 1 }, { width: 550, itemsToShow: 2, itemsToScroll: 2 }, { width: 768, itemsToShow: 3 }, { width: 1200, itemsToShow: 4 }, ]; const datashow = data.map((item) => ( // 添加key属性修复React列表渲染警告 <div key={item.id} className="card"> <img src={item.package_image} className="card-img-top" alt={item.details_title_en} style={{ width: "100%", height: "20vw", objectFit: "cover" }} /> <div className="card-body"> <h5 className="card-title">{item.details_title_en}</h5> <p className="balneo"> <i className="fa-solid fa-location-dot" style={{ paddingRight: "5px" }} ></i> {item.city_name_en} </p> <p className="balneo"> Package Period: <span style={{ fontWeight: "bold" }}> From </span> <span style={{ color: "#ff5959" }}> {item.period_from}</span> <span style={{ fontWeight: "bold" }}> To </span>{" "} <span style={{ color: "#ff5959" }}> {item.period_to}</span> </p> <div> <p className="paragraph"> <span style={{ color: "var(--yellow-color)" }}> {/* 优化星级渲染逻辑,避免重复代码 */} {item.package_rate && item.package_rate > 0 ? Array.from({ length: item.package_rate }, (_, idx) => ( <i key={idx} className="fa-solid fa-star"></i> )) : ""} </span> </p> </div> <p className="card-text">{item.city_details_text1_en}</p> </div> </div> )); return ( <div className="container pt-5 pb-5"> <h3 className="fw-bold pt-5 text-center mb-5">Featured Listings</h3> <Carousel breakPoints={breakPoints} enableAutoPlay autoPlaySpeed={3000}> {datashow} </Carousel> </div> ); }
修复说明
- 取消异步请求:使用
AbortController,组件卸载时自动终止未完成的fetch请求,避免后续状态更新操作 - 错误过滤:捕获并忽略请求取消导致的
AbortError,减少控制台无效报错 - 代码优化:
- 给列表项添加
key属性,符合React列表渲染规范 - 重构星级渲染逻辑,用
Array.from替代多层嵌套的三元判断,简化代码 - 统一使用React标准属性
className替换原生class
- 给列表项添加
内容的提问来源于stack exchange,提问作者Nageeb Darwish
相关产品推荐
相关产品推荐

