React中@render仅打印3次?为何与预期4次渲染不符?
React状态更新次数疑问解析
问题描述
我原本预期会触发4次渲染:
- 初始渲染;
setData触发的第二次渲染;setPageStatus触发的第三次渲染;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次
@render,同时执行空依赖的useEffect,调用queryData后进入await等待状态。 - 异步回调同步阶段的合并更新:1秒后Promise resolve,
queryData继续执行:setData(pageData)和setPageStatus("normal")是在同一个异步回调的同步执行环节触发的两次状态更新,React会自动将这两个更新合并为一次渲染,因此这里只触发第2次@render,而非你预期的两次独立渲染。
- 依赖触发的更新:当
data从null变为1后,依赖[data]的useEffect执行,调用setDeps(data)触发第3次@render。
所以最终总共打印3次@render,是合并了setData与setPageStatus的更新,而非setPageStatus与setDeps的更新。
注:React 18版本默认在所有场景(包括异步回调、定时器等)启用自动批量更新,若需强制同步更新单个状态操作,可使用flushSync包裹对应的setState调用。
内容的提问来源于stack exchange,提问作者WangYuanFuRong
相关产品推荐
相关产品推荐

