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

React中@render仅打印3次?为何与预期4次渲染不符?

React状态更新次数疑问解析

问题描述

我原本预期会触发4次渲染:

  1. 初始渲染;
  2. setData触发的第二次渲染;
  3. setPageStatus触发的第三次渲染;
  4. setDeps触发的第四次渲染;
    但实际仅打印了3次@render。请问是否是React合并了setPageStatus与setDeps的状态更新操作?

相关代码

app.tsx

import "./App.css";
import useHome from './hooks/useHome';

function App() {
  useHome();
  return <></>;
}

export default App;

hooks/useHome.ts

import { useEffect, useState } from "react";

const query = (): Promise<number> =>
  new Promise((resolve) =>
    setTimeout(() => {
      resolve(1);
    }, 1000),
  );

const useHome = () => {
  const [pageStatus, setPageStatus] = useState<string>("loading");
  const [data, setData] = useState<number | null>(null);
  const [deps, setDeps] = useState(data);

  const queryData = async () => {
    setPageStatus("loading");
    try {
      const pageData = await query();
      setData(pageData); // 触发第二次渲染
      setPageStatus("normal"); // 触发第三次渲染
    } catch (e) {
      setPageStatus("error");
    }
  };

  useEffect(() => {
    queryData(); 
  }, []);

  useEffect(() => {
    setDeps(data); // 触发第四次渲染
  }, [data]);

  console.log("@render"); // 共打印3次

  return {
    deps,
    data,
    pageStatus,
  };
};

export default useHome;

原因分析

核心是React的自动批量更新机制,实际渲染流程如下:

  1. 初始渲染:组件首次挂载,打印第1次@render,同时执行空依赖的useEffect,调用queryData后进入await等待状态。
  2. 异步回调同步阶段的合并更新:1秒后Promise resolve,queryData继续执行:
    • setData(pageData)和setPageStatus("normal")是在同一个异步回调的同步执行环节触发的两次状态更新,React会自动将这两个更新合并为一次渲染,因此这里只触发第2次@render,而非你预期的两次独立渲染。
  3. 依赖触发的更新:当data从null变为1后,依赖[data]的useEffect执行,调用setDeps(data)触发第3次@render。

所以最终总共打印3次@render,是合并了setData与setPageStatus的更新,而非setPageStatus与setDeps的更新。

注:React 18版本默认在所有场景(包括异步回调、定时器等)启用自动批量更新,若需强制同步更新单个状态操作,可使用flushSync包裹对应的setState调用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 11:24:57