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

React Strict Mode中组件卸载后重新挂载仍保留状态的原因咨询

React Strict Mode中组件卸载后重新挂载仍保留状态的原因咨询

你遇到的这个看似反直觉的行为,其实是React Strict Mode在开发环境下特意设计的特性,并不是组件生命周期的bug,下面我来详细解释背后的逻辑:

一、Strict Mode的核心目的

Strict Mode的作用是帮开发者提前发现代码中的潜在问题,比如未正确清理的副作用、不安全的生命周期用法等。为了实现这个目标,它在开发环境下会执行一些额外的检查,其中就包括模拟组件“卸载后立即重新挂载”的场景——这正是你看到状态被保留的原因。

二、状态保留的具体原因

在开发模式的Strict Mode中,当组件被卸载(比如你通过修改key触发的卸载),React并不会真正销毁组件的状态快照,而是会暂时保留它。当组件紧接着被重新挂载时,React会恢复这个状态,以此来模拟未来React版本中可能出现的“组件被卸载后复用”的优化场景,同时也能帮你检测:

  • 你的副作用清理函数是否真的彻底清除了所有资源(比如订阅、定时器)
  • 你的组件是否依赖“卸载后状态完全销毁”的假设来工作(如果是,那在未来的React版本中可能会出问题)

三、结合你的代码示例分析

先看你的Counter组件及相关代码:

import { useState, useEffect } from "react";

function Counter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    console.log("Counter component mounted");
    setCount((prev) => {
      console.log("prev", prev);
      return prev + 1;
    });

    return () => {
      console.log("Counter component unmounted - cleanup function called");
    };
  }, []);

  const handleIncrement = () => {
    setCount((prev) => {
      console.log("Previous count:", prev);
      return prev + 1;
    });
  };

  return (
    <div className="counter">
      <h2>Count: {count}</h2>
      <button onClick={handleIncrement}>Count Up</button>
    </div>
  );
}

function App() {
  const [theKey, setTheKey] = useState(1);

  useEffect(() => {
    setTimeout(() => {
      alert("key is changed. so component will be unmount and re-mount");
      setTheKey(2);
    }, 3000);
  }, []);

  return (
    <div className="App">
      <h1> React Strict Mode Unmount Test. Why prev state is preserved even unmounted ? </h1>
      <Counter key={theKey} />
    </div>
  );
}

export default App;

入口文件代码:

import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App";

const rootElement = document.getElementById("root");
const root = createRoot(rootElement);

root.render(
  <StrictMode>
    <App />
  </StrictMode>
);

在Strict Mode的开发环境下,流程是这样的:

  1. 第一次挂载Counter时,useState初始化count为0,useEffect触发后把count改成1;
  2. 3秒后key变为2,触发组件卸载,此时React保留了count=1的状态快照;
  3. 重新挂载Counter时,React没有重新初始化count为0,而是恢复了之前的count=1,所以useEffect里的prev就是1,最终count变成2。

四、生产环境的表现

放心,这个状态保留的行为只会在开发环境存在,生产环境下Strict Mode的额外检查会被禁用,组件卸载后状态会被彻底销毁,重新挂载时会从useState的初始值开始。

五、如何应对这个情况

  • 如果你只是开发阶段的测试,不需要特殊处理,这是Strict Mode帮你提前发现潜在问题的方式;
  • 如果你的组件确实需要在卸载后完全清除状态,可以确保在useEffect的清理函数中处理相关逻辑(比如清理外部依赖的资源);
  • 接受这个行为,因为它是React为了未来的优化做的提前兼容测试。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 14:29:36