flushSync

易犯错误

使用 flushSync 不常见,可能会影响你的应用性能。

🌐 Using flushSync is uncommon and can hurt the performance of your app.

flushSync 允许你强制 React 在提供的回调函数中同步刷新任何更新。这确保了 DOM 会立即更新。

flushSync(callback)

参考

🌐 Reference

flushSync(callback)

调用 flushSync 以强制 React 刷新任何挂起的工作并同步更新 DOM。

🌐 Call flushSync to force React to flush any pending work and update the DOM synchronously.

import { flushSync } from 'react-dom';

flushSync(() => {
setSomething(123);
});

大多数情况下,可以避免使用 flushSync。将 flushSync 作为最后的手段。

🌐 Most of the time, flushSync can be avoided. Use flushSync as last resort.

查看更多示例。

参数

🌐 Parameters

  • callback:一个函数。React 会立即调用这个回调并同步刷新它包含的任何更新。它也可能刷新任何待处理的更新、Effects,或 Effects 内的更新。如果由于这个 flushSync 调用而导致更新暂停,备用内容可能会被重新显示。

返回

🌐 Returns

flushSync 返回 undefined

注意事项

🌐 Caveats

  • flushSync 会显著影响性能。请谨慎使用。
  • flushSync 可能会强制待处理的 Suspense 边界显示其 fallback 状态。
  • flushSync 可能会运行待处理的效果,并在返回之前同步应用它们包含的任何更新。
  • flushSync 可能在回调之外刷新更新,以在必要时刷新回调内的更新。例如,如果有来自点击的待处理更新,React 可能会在刷新回调内的更新之前先刷新这些更新。

用法

🌐 Usage

刷新第三方集成的更新

🌐 Flushing updates for third-party integrations

在与第三方代码(例如浏览器 API 或 UI 库)集成时,可能需要强制 React 刷新更新。使用 flushSync 来强制 React 在回调内部同步刷新任何 状态更新 :

flushSync(() => {
setSomething(123);
});
// By this line, the DOM is updated.

这确保了在下一行代码运行时,React 已经更新了 DOM。

🌐 This ensures that, by the time the next line of code runs, React has already updated the DOM.

使用 flushSync 不常见,而且频繁使用它可能会显著影响你应用的性能。 如果你的应用只使用 React API,并且不与第三方库集成,那么 flushSync 应该是不必要的。

但是,它有助于与浏览器 API 等第三方代码集成。

🌐 However, it can be helpful for integrating with third-party code like browser APIs.

一些浏览器 API 期望在回调中的结果在回调结束时同步写入 DOM,以便浏览器可以对渲染后的 DOM 进行某些操作。在大多数情况下,React 会自动为你处理这一点。但在某些情况下,可能需要强制同步更新。

🌐 Some browser APIs expect results inside of callbacks to be written to the DOM synchronously, by the end of the callback, so the browser can do something with the rendered DOM. In most cases, React handles this for you automatically. But in some cases it may be necessary to force a synchronous update.

例如,浏览器 onbeforeprint API 允许你在打印对话框打开之前立即更改页面。这对于应用自定义打印样式非常有用,可以让文档在打印时显示得更好。在下面的示例中,你在 onbeforeprint 回调中使用 flushSync 来立即将 React 状态“刷新”到 DOM 中。然后,当打印对话框打开时,isPrinting 显示“yes”。

🌐 For example, the browser onbeforeprint API allows you to change the page immediately before the print dialog opens. This is useful for applying custom print styles that allow the document to display better for printing. In the example below, you use flushSync inside of the onbeforeprint callback to immediately “flush” the React state to the DOM. Then, by the time the print dialog opens, isPrinting displays “yes”:

import { useState, useEffect } from 'react';
import { flushSync } from 'react-dom';

export default function PrintApp() {
  const [isPrinting, setIsPrinting] = useState(false);

  useEffect(() => {
    function handleBeforePrint() {
      flushSync(() => {
        setIsPrinting(true);
      })
    }

    function handleAfterPrint() {
      setIsPrinting(false);
    }

    window.addEventListener('beforeprint', handleBeforePrint);
    window.addEventListener('afterprint', handleAfterPrint);
    return () => {
      window.removeEventListener('beforeprint', handleBeforePrint);
      window.removeEventListener('afterprint', handleAfterPrint);
    }
  }, []);

  return (
    <>
      <h1>isPrinting: {isPrinting ? 'yes' : 'no'}</h1>
      <button onClick={() => window.print()}>
        Print
      </button>
    </>
  );
}

没有 flushSync,打印对话框将显示 isPrinting 为“否”。这是因为 React 异步批量更新,并且打印对话框在状态更新之前显示。

🌐 Without flushSync, the print dialog will display isPrinting as “no”. This is because React batches the updates asynchronously and the print dialog is displayed before the state is updated.

易犯错误

flushSync 可能会显著影响性能,并可能意外地迫使待处理的 Suspense 边界显示其回退状态。

大多数情况下,可以避免使用 flushSync,所以把 flushSync 作为最后的手段。

🌐 Most of the time, flushSync can be avoided, so use flushSync as a last resort.


故障排除

🌐 Troubleshooting

我遇到了一个错误:“flushSync 是在生命周期方法内部调用的”

🌐 I’m getting an error: “flushSync was called from inside a lifecycle method”

React 不能在渲染过程中间 flushSync。如果你这么做,它会无操作并发出警告:

🌐 React cannot flushSync in the middle of a render. If you do, it will noop and warn:

Console

这包括在以下内容中调用 flushSync

🌐 This includes calling flushSync inside:

  • 正在渲染组件。
  • useLayoutEffectuseEffect 钩子。
  • 类组件生命周期方法。

例如,在 Effect 中调用 flushSync 会什么也不做并发出警告:

🌐 For example, calling flushSync in an Effect will noop and warn:

import { useEffect } from 'react';
import { flushSync } from 'react-dom';

function MyComponent() {
useEffect(() => {
// 🚩 Wrong: calling flushSync inside an effect
flushSync(() => {
setSomething(newValue);
});
}, []);

return <div></div>;
}

为了解决这个问题,你通常需要将 flushSync 调用移动到一个事件中:

🌐 To fix this, you usually want to move the flushSync call to an event:

function handleClick() {
// ✅ Correct: flushSync in event handlers is safe
flushSync(() => {
setSomething(newValue);
});
}

如果很难移动到某个事件,你可以在微任务中延迟 flushSync

🌐 If it’s difficult to move to an event, you can defer flushSync in a microtask:

useEffect(() => {
// ✅ Correct: defer flushSync to a microtask
queueMicrotask(() => {
flushSync(() => {
setSomething(newValue);
});
});
}, []);

这将允许当前渲染完成并安排另一个同步渲染来刷新更新。

🌐 This will allow the current render to finish and schedule another syncronous render to flush the updates.

易犯错误

flushSync 可能会显著影响性能,但这种特定模式对性能的影响甚至更大。在将 flushSync 作为微任务中的应急手段调用之前,请先尝试其他所有选项。