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

React中state值未变化时组件仍重渲染的原因解析

核心测试代码
import { useState } from "react";

export default function App() {
  console.log("rendered...")
  const [count, setCount] = useState(0);

  const increaseCount = () => {
    setCount(count + 1);
  };

  const setFourValue = () => {
    setCount(4);
  };
  return (
    <div className="App">
      <div
        style={{ display: "flex", alignItems: "center", columnGap: ".25rem" }}
      >
        <button onClick={increaseCount}>Increase</button>
        <button onClick={setFourValue}>Set 4</button>
        <span>{count}</span>
      </div>
    </div>
  );
}
现象产生的根本原因

这个表现是React状态更新调度逻辑的固有设计,和值比较规则、渲染跳出(bailout)的触发时机直接相关:

  • React调用setState时不会立刻对比新旧值决定是否跳过渲染,所有状态更新会先进入调度队列。新旧状态的相等判断用Object.is实现,只有判定完全相等时才有机会跳过渲染。
  • 当你通过Increase按钮把count累加到4时,最后一次状态更新是setCount(4),这次更新完成组件重渲染后,组件闭包内捕获的count值、React记录的当前组件状态值都为4。
  • 第一次点击Set 4触发setCount(4)时,React虽然对比发现新旧值相等,但不会直接跳出渲染:它会执行一次组件的render函数做校验,遍历检查组件子树是否存在待处理的更新、上下文变化等需要触发更新的场景,这次校验不会产生实际的DOM修改,只是走一遍render流程确认无变更,所以你会看到控制台打印rendered...。
  • 等这次校验渲染完成后,React会记录当前count值已经稳定为4,后续再点击Set 4触发同值更新时,React在调度阶段就会判定新旧值完全一致且已经完成过校验,直接触发bailout逻辑,完全跳过组件及子树的render流程,也就不会再打印渲染日志。

补充说明:这个机制只针对组件完成一次渲染后,首次触发的同值状态更新生效;如果同值更新是在已经被判定跳过的更新队列里重复触发,React会直接合并丢弃,不会重复执行校验渲染。

内容的提问来源于stack exchange,提问作者Umut Palabiyik

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 10:30:39