落とし穴

flushSync の使用は一般的ではなく、アプリのパフォーマンスを低下させる可能性があります。

flushSync は、渡されたコールバック関数内のあらゆる更新作業を強制的かつ同期的にフラッシュ (flush) するように React に指示します。これにより、DOM が直ちに更新されることが保証されます。

flushSync(callback)

リファレンス

flushSync(callback)

flushSync を呼び出して、保留中の作業をフラッシュし、DOM を同期的に更新するよう React に強制します。

import { flushSync } from 'react-dom';

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

ほとんどの場合、flushSync の使用は避けることができます。flushSync は最後の手段として使用してください。

さらに例を見る

引数

  • callback: 関数。React はこのコールバックを直ちに呼び出し、そこに含まれるすべての更新作業を同期的にフラッシュします。また、保留中の更新、エフェクト、エフェクト内の更新もフラッシュすることがあります。この flushSync 呼び出しの結果として更新のサスペンドが起きると、フォールバックが再表示される可能性があります。

返り値

flushSyncundefined を返します。

注意点

  • flushSync can significantly hurt performance. Use sparingly.
  • flushSync may force pending Suspense boundaries to show their fallback state.
  • flushSync may run pending Effects and synchronously apply any updates they contain before returning.
  • flushSync may 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.

使用法

サードパーティコードとの統合のために更新作業をフラッシュ

ブラウザ API や UI ライブラリなどのサードパーティのコードと統合作業を行う際には、React に更新をフラッシュするように強制する必要があるかもしれません。コールバック内の任意の state 更新 を同期的にフラッシュするよう React に強制するために flushSync を使用します。

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

これにより、コードの次の行が実行される時点で、React はすでに DOM を更新しているということが保証されます。

flushSync の使用は一般的ではなく、頻繁に使用するとアプリのパフォーマンスが大幅に低下する可能性があります。アプリが React の API のみを使用し、サードパーティのライブラリとの結合がない場合、flushSync は不要のはずです。

しかし、これはブラウザの API などのサードパーティのコードとの統合に役立つことがあります。

一部のブラウザの API は、コールバック内の結果がコールバックの終了時点までに同期的に DOM に書き込まれ、ブラウザがレンダーされた DOM を操作できるようになることを期待しています。ほとんどの場合 React はこれを自動的に処理します。しかし、一部のケースでは同期的な更新を強制する必要があるかもしれません。

例えば、ブラウザの onbeforeprint API を用いると、印刷ダイアログが開く直前にページを変更することができます。これは、ドキュメントが印刷用により良く表示されるよう、カスタム印刷スタイルを適用する際に有用です。以下の例では、onbeforeprint コールバック内で flushSync を使用して、React の state を即座に 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 が更新を非同期的にバッチ(束ね)処理するため、state の更新処理がなされる前に印刷ダイアログが表示されるからです。

落とし穴

flushSync はパフォーマンスを大幅に低下させ、保留中のサスペンスバウンダリのフォールバックが予期せず表示されてしまう可能性があります。

ほとんどの場合、flushSync の使用は避けることができるので、flushSync は最後の手段として使用してください。