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

在useEffect中使用flushSync是否等同于useLayoutEffect?

在useEffect中使用flushSync与useLayoutEffect的差异

先给结论:这两种写法功能并不一致,你的理解存在偏差,核心差异体现在执行时机和用户视觉体验上,具体分析如下:

1. 核心概念本质区别

  • useLayoutEffect:属于React commit阶段的同步钩子,在DOM更新完成后、浏览器开始绘制页面之前立即执行。它的代码会阻塞浏览器绘制,确保内部所有状态更新完成后,页面才会首次显示给用户。
  • flushSync:仅作用是强制React同步执行回调内的状态更新,确保DOM立即更新,但它无法改变自身所在代码块的执行时机——如果放在useEffect里,整体依然是在浏览器绘制完成之后才会触发。

2. 两段代码的实际表现差异

第一段:useEffect嵌套flushSync

const App = () => {
    const [name, setName] = React.useState("Leonardo");
    React.useEffect(() => {
        ReactDOM.flushSync(() => {
            for (let index = 1; index <= 100000; index++) { // 模拟阻塞操作
                console.log(index);
            }
            setName("Jose");
        });
    });
    return (
        <div>
            <h1>Hello {name}</h1>
        </div>
    );
};

执行流程:

  1. React首次渲染,DOM生成后浏览器完成绘制,用户会先看到Hello Leonardo
  2. 浏览器绘制结束后,触发useEffect回调
  3. 循环代码阻塞线程,此时页面已经显示Leonardo
  4. 循环结束后,flushSync强制同步更新name状态,DOM更新为Hello Jose
  5. 浏览器重新绘制,用户会看到从Leonardo闪跳至Jose的过程

第二段:直接使用useLayoutEffect

React.useLayoutEffect(() => {
  for (let index = 1; index <= 100000; index++) {
   console.log(index);
  }
  setName("Jose");
});

执行流程:

  1. React首次渲染生成DOM,但浏览器尚未开始绘制页面
  2. 先执行useLayoutEffect回调,循环阻塞线程(此时用户看不到任何页面内容)
  3. 循环结束后更新name状态,React同步更新DOM
  4. DOM更新完成后,浏览器绘制页面,用户直接看到Hello Jose,不会出现视觉闪烁

3. 总结

flushSync只是强制同步处理回调内的状态更新,但无法改变外层useEffect的异步执行时机(浏览器绘制后);而useLayoutEffect本身就运行在绘制前的同步阶段,天然能确保状态更新完成后再展示页面,避免视觉闪烁。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 06:30:37