flushSync
Подводный камень
Использование flushSync встречается редко и может снизить производительность приложения.
flushSync позволяет принудительно синхронно сбросить все обновления внутри переданного колбэка. Это гарантирует немедленное обновление DOM.
flushSync(callback)
Справочник
flushSync(callback)
Вызовите flushSync, чтобы принудительно сбросить все ожидающие обновления и синхронно обновить DOM.
import { flushSync } from 'react-dom';
flushSync(() => {
setSomething(123);
}); В большинстве случаев можно обойтись без flushSync. Используйте flushSync только в крайнем случае.
Другие примеры приведены ниже.
Параметры
-
callback: функция. React немедленно вызовет этот колбэк и синхронно сбросит все содержащиеся в нём обновления. Также могут быть сброшены все ожидающие обновления, эффекты и обновления внутри эффектов. Если в результате вызоваflushSyncобновление приостанавливается, резервные варианты могут снова отобразиться.
Возвращаемое значение
flushSync возвращает undefined.
Предостережения
-
flushSyncможет значительно снизить производительность. Используйте его экономно. -
flushSyncможет заставить ожидающие границы Suspense отображать состояниеfallback. -
flushSyncможет запускать ожидающие эффекты и синхронно применять содержащиеся в них обновления перед возвратом. -
flushSyncпри необходимости может сбрасывать обновления за пределами колбэка, чтобы сбросить обновления внутри него. Например, если ожидают обработки обновления после клика, React может сбросить их до сброса обновлений внутри колбэка.
Использование
Сброс обновлений для интеграции со сторонними библиотеками
При интеграции со сторонним кодом, например с API браузера или библиотеками пользовательского интерфейса, может потребоваться принудительно сбросить обновления React. Используйте flushSync, чтобы синхронно сбросить все обновления состояния внутри колбэка:
flushSync(() => {
setSomething(123);
});
// By this line, the DOM is updated. Это гарантирует, что к моменту выполнения следующей строки кода React уже обновит DOM.
Использование flushSync встречается редко, а частое применение может значительно снизить производительность приложения. Если приложение использует только API React и не интегрируется со сторонними библиотеками, flushSync не должно понадобиться.
Однако это может быть полезно при интеграции со сторонним кодом, например с API браузера.
Некоторые API браузера ожидают, что результаты внутри колбэков будут синхронно записаны в DOM до завершения колбэка, чтобы браузер мог выполнить действие с отрисованным DOM. В большинстве случаев React автоматически делает это за вас. Но иногда может потребоваться принудительное синхронное обновление.
Например, API браузера onbeforeprint позволяет изменить страницу непосредственно перед открытием диалогового окна печати. Это полезно для применения пользовательских стилей печати, которые улучшают отображение документа при печати. В приведённом ниже примере flushSync используется внутри колбэка onbeforeprint, чтобы немедленно «сбросить» состояние React в DOM. Поэтому к моменту открытия диалогового окна печати isPrinting отображает значение «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 асинхронно группирует обновления, и диалоговое окно печати открывается до обновления состояния.
Подводный камень
flushSync может значительно снизить производительность и неожиданно заставить ожидающие границы Suspense отобразить резервное состояние.
В большинстве случаев можно обойтись без flushSync, поэтому используйте flushSync только в крайнем случае.
Устранение неполадок
Появляется ошибка: «flushSync was called from inside a lifecycle method»
React не может flushSync во время рендеринга. Если это сделать, вызов ничего не выполнит и появится предупреждение:
Это относится и к вызову flushSync внутри:
- рендеринга компонента.
-
хуков
useLayoutEffectилиuseEffect. - методов жизненного цикла классового компонента.
Например, вызов flushSync в эффекте ничего не выполнит и вызовет предупреждение:
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 в обработчик события:
function handleClick() {
// ✅ Correct: flushSync in event handlers is safe
flushSync(() => {
setSomething(newValue);
});
} Если перенести вызов в обработчик события сложно, можно отложить flushSync до микрозадачи:
useEffect(() => {
// ✅ Correct: defer flushSync to a microtask
queueMicrotask(() => {
flushSync(() => {
setSomething(newValue);
});
});
}, []); Это позволит завершить текущий рендеринг и запланировать ещё один синхронный рендеринг для сброса обновлений.
Подводный камень
flushSync может значительно снизить производительность, но этот конкретный подход ещё сильнее ухудшает её. Прежде чем прибегать к flushSync в микрозадаче как к крайнему средству, исчерпайте все остальные варианты.
© 2013–present Facebook Inc.
Licensed under the Creative Commons Attribution 4.0 International Public License.
https://react.dev/reference/react-dom/flushSync