flushSync 允许你强制 React 同步刷新提供的回调中的任何更新。这确保了 DOM 立即更新。
¥flushSync lets you force React to flush any updates inside the provided callback synchronously. This ensures that the DOM is updated immediately.
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 将立即调用此回调并同步刷新它包含的任何更新。它还可能刷新任何挂起的更新、副作用或副作用内部的更新。如果更新由于此flushSync调用而暂停,则可能会重新显示回退。¥
callback: A function. React will immediately call this callback and flush any updates it contains synchronously. It may also flush any pending updates, or Effects, or updates inside of Effects. If an update suspends as a result of thisflushSynccall, the fallbacks may be re-shown.
返回
¥Returns
flushSync 返回 undefined。
¥flushSync returns undefined.
注意事项
¥Caveats
-
flushSync会严重影响性能。谨慎使用。¥
flushSynccan significantly hurt performance. Use sparingly. -
flushSync可能会强制挂起的 Suspense 边界显示其fallback状态。¥
flushSyncmay force pending Suspense boundaries to show theirfallbackstate. -
flushSync可以运行待处理的效果并在返回之前同步应用它们包含的任何更新。¥
flushSyncmay run pending Effects and synchronously apply any updates they contain before returning. -
flushSync可能会在必要时刷新回调外部的更新以刷新回调内部的更新。例如,如果有来自点击的未决更新,React 可能会在刷新回调内的更新之前刷新这些更新。¥
flushSyncmay flush updates outside the callback when necessary to flush the updates inside the callback. For example, if there are pending updates from a click, React may flush those before flushing the updates inside the callback.
用法
¥Usage
刷新第三方集成的更新
¥Flushing updates for third-party integrations
当与第三方代码(如浏览器 API 或 UI 库)集成时,可能需要强制 React 刷新更新。使用 flushSync 强制 React 同步刷新回调中的任何 状态 updates:
¥When integrating with third-party code such as browser APIs or UI libraries, it may be necessary to force React to flush updates. Use flushSync to force React to flush any state updates inside the callback synchronously:
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 应该是不必要的。
¥Using flushSync is uncommon, and using it often can significantly hurt the performance of your app. If your app only uses React APIs, and does not integrate with third-party libraries, flushSync should be unnecessary.
但是,它有助于与浏览器 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 显示为 “no”。这是因为 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.
故障排除
¥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:
这包括在内部调用 flushSync:
¥This includes calling flushSync inside:
-
正在渲染组件。
¥rendering a component.
-
useLayoutEffect或useEffect钩子。¥
useLayoutEffectoruseEffecthooks. -
类组件生命周期方法。
¥Class component lifecycle methods.
例如,在副作用中调用 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.