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

求助:页面刷新时React组件出现「Can't perform a React state update on an unmounted component」警告的原因及解决方法

解决React状态更新在卸载组件上的警告问题

这个警告出现的核心原因很明确:当页面刷新或者路由切换时,你的loadSingleCourse异步请求可能还没完成,但组件已经被卸载了。等请求最终返回结果后,再调用setCourse或setLoading,就会试图在一个已经不存在的组件实例上更新状态,这就触发了React的内存泄漏警告。

具体修复方案

我们可以在useEffect中添加一个挂载状态标志,用来跟踪组件是否还处于活跃挂载状态,只有当组件挂载时才执行状态更新操作。修改后的完整代码如下:

import { useRouter } from "next/router";
import { useEffect, useState } from "react";
import axios from "axios"; // 补充显式导入axios,避免隐式依赖问题

const CourseDetail = () => { // 补充组件函数定义,你的原代码遗漏了这部分
  const [loading, setLoading] = useState(true);
  const [course, setCourse] = useState({});
  const router = useRouter();
  const { slug } = router.query;

  useEffect(() => {
    // 初始化挂载状态标志
    let isMounted = true;
    setLoading(true);

    const loadSingleCourse = async () => {
      try {
        const { data } = await axios.get(`/api/course/${slug}`);
        // 仅当组件处于挂载状态时,才更新状态
        if (isMounted) {
          setCourse(data);
          setLoading(false);
        }
      } catch (error) {
        // 错误处理也要检查挂载状态,避免无效更新
        if (isMounted) {
          setLoading(false);
          console.error("课程加载失败:", error);
        }
      }
    };

    loadSingleCourse();

    // 组件卸载时的清理函数:将挂载标志置为false
    return () => {
      isMounted = false;
    };
  }, [slug]);

  // 你的渲染逻辑(注意修正label的for属性为htmlFor)
  return (
    {loading ? (
      "Loading.."
    ) : (
      <>
        <div className="max-w-2xl px-6 py-16 mx-auto space-y-12">
          <article className="space-y-8 ">
            <div className="space-y-6">
              <h1 className="text-4xl font-bold md:tracking-tight md:text-5xl text-accent">
                {course.title}
              </h1>
              <div className="flex flex-col items-start justify-between w-full md:flex-row md:items-center dark:text-coolGray-400">
                <div className="flex items-center md:space-x-2">
                  <img src="https://source.unsplash.com/75x75/?portrait" alt="" className="w-4 h-4 border rounded-full dark:bg-coolGray-500 dark:border-coolGray-700" />
                  <p className="text-sm">
                    {course.instructor.name} • {course.createdAt}
                  </p>
                </div>
              </div>
            </div>
            <div className="dark:text-coolGray-500">
              <p>{course.description}</p>
            </div>
          </article>
          <div>
            <div className="flex flex-wrap py-6 space-x-2 border-t border-dashed dark:border-coolGray-400">
              <p className="px-3 py-1 rounded-md hover:underline bg-primary text-accent">
                #{course.category}
              </p>
              <p className="px-3 py-1 rounded-md hover:underline bg-accent text-primary">
                {course.lessons.length} Lessons
              </p>
              <div>
                {/* 修正JSX中的for属性为htmlFor */}
                <label htmlFor="add-lesson-modal" className="border-2 flex align-center items-center text-accent py-1 rounded-md px-2 cursor-pointer" >
                  <svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor" >
                    <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm1-11a1 1 0 10-2 0v2H7a1 1 0 100 2h2v2a1 1 0 102 0v-2h2a1 1 0 100-2h-2V7z" clip-rule="evenodd" />
                  </svg>
                  Add Lesson
                </label>
                <input type="checkbox" id="add-lesson-modal" className="modal-toggle" />
                <div className="modal">
                  <div className="modal-box overflow-scroll">
                    <AddLessonForm handleAdd={handleAddLesson} values={values} setValues={setValues} uploading={uploading} course={course} uploadVideoText={uploadVideoText} handleLessonVideo={handleLessonVideo} uploadProgress={uploadProgress} />
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </>
    )}
  );
};

export default CourseDetail;

关键修复点说明

  1. 挂载状态标志isMounted:在useEffect内部初始化,组件挂载时为true,卸载时通过返回的清理函数置为false,确保异步操作完成后只在活跃组件上更新状态。
  2. 错误处理增强:添加try/catch块捕获请求错误,并且在错误处理中也检查挂载状态,避免无效的状态更新。
  3. JSX细节修正:将label标签的for属性改为htmlFor,这是React JSX的规范要求,避免额外的控制台警告。

内容的提问来源于stack exchange,提问作者Debanjan Tewary

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 06:52:42