useInsertionEffect
を使用すると、レイアウト効果が実行される前にDOMに要素を挿入できます。
useInsertionEffect(setup, dependencies?)
リファレンス
useInsertionEffect(setup, dependencies?)
レイアウトを読み取る必要がある可能性のある効果が発生する前にスタイルを挿入するには、useInsertionEffect
を呼び出します。
import { useInsertionEffect } from 'react';
// Inside your CSS-in-JS library
function useCSS(rule) {
useInsertionEffect(() => {
// ... inject <style> tags here ...
});
return rule;
}
パラメータ
-
setup
:エフェクトのロジックを含む関数。 setup関数は、オプションでクリーンアップ関数を返すこともできます。コンポーネントがDOMに追加された後、レイアウト効果が発生する前に、Reactはsetup関数を実行します。依存関係が変更された再レンダリングの後、Reactは最初に古い値でクリーンアップ関数(提供されている場合)を実行し、次に新しい値でsetup関数を実行します。コンポーネントがDOMから削除されると、Reactはクリーンアップ関数を実行します。 -
オプション
dependencies
:setup
コード内で参照されるすべてのリアクティブ値のリスト。リアクティブ値には、props、状態、コンポーネント本体内で直接宣言されたすべての変数と関数が含まれます。リンターがReact用に設定されている場合、すべてのリアクティブ値が依存関係として正しく指定されていることを検証します。依存関係のリストには、一定数のアイテムが含まれており、[dep1, dep2, dep3]
のようにインラインで記述する必要があります。Reactは、Object.is
比較アルゴリズムを使用して、各依存関係とその前の値を比較します。依存関係をまったく指定しない場合、エフェクトはコンポーネントの再レンダリングごとに再実行されます。
戻り値
useInsertionEffect
は undefined
を返します。
注意事項
- エフェクトはクライアント側でのみ実行されます。サーバーサイドレンダリング中は実行されません。
useInsertionEffect
の内部から状態を更新することはできません。useInsertionEffect
が実行される時点では、refs はまだアタッチされていません。useInsertionEffect
は、DOM が更新される前または後に実行される場合があります。DOM が特定の時間に更新されることに依存すべきではありません。- 他の種類のエフェクトは、各エフェクトに対してクリーンアップを実行してから各エフェクトに対してセットアップを実行しますが、
useInsertionEffect
は、一度に1つのコンポーネントに対してクリーンアップとセットアップの両方を実行します。これにより、クリーンアップ関数とセットアップ関数が「インターリーブ」されます。
使用方法
CSS-in-JSライブラリからの動的スタイルの挿入
従来、プレーンなCSSを使用してReactコンポーネントのスタイルを設定していました。
// In your JS file:
<button className="success" />
// In your CSS file:
.success { color: green; }
CSSファイルを作成する代わりに、JavaScriptコードに直接スタイルを記述することを好むチームもあります。これは通常、CSS-in-JSライブラリまたはツールを使用する必要があります。CSS-in-JSには3つの一般的なアプローチがあります。
- コンパイラによるCSSファイルへの静的抽出
- インラインスタイル、例:
<div style={{ opacity: 1 }}>
<style>
タグの実行時挿入
CSS-in-JSを使用する場合は、最初の2つのアプローチの組み合わせ(静的スタイルにはCSSファイル、動的スタイルにはインラインスタイル)をお勧めします。実行時の<style>
タグの挿入は、次の2つの理由からお勧めしません。
- 実行時挿入は、ブラウザがスタイルをはるかに頻繁に再計算することを強制します。
- Reactライフサイクルの不適切なタイミングで実行されると、実行時挿入は非常に遅くなる可能性があります。
最初の問題は解決できませんが、useInsertionEffect
を使用すると、2番目の問題を解決できます。
レイアウトエフェクトが実行される前にスタイルを挿入するには、useInsertionEffect
を呼び出します。
// Inside your CSS-in-JS library
let isInserted = new Set();
function useCSS(rule) {
useInsertionEffect(() => {
// As explained earlier, we don't recommend runtime injection of <style> tags.
// But if you have to do it, then it's important to do in useInsertionEffect.
if (!isInserted.has(rule)) {
isInserted.add(rule);
document.head.appendChild(getStyleForRule(rule));
}
});
return rule;
}
function Button() {
const className = useCSS('...');
return <div className={className} />;
}
useEffect
と同様に、useInsertionEffect
はサーバー側では実行されません。サーバー側で使用されたCSSルールを収集する必要がある場合は、レンダリング中に実行できます。
let collectedRulesSet = new Set();
function useCSS(rule) {
if (typeof window === 'undefined') {
collectedRulesSet.add(rule);
}
useInsertionEffect(() => {
// ...
});
return rule;
}
実行時挿入をuseInsertionEffect
にアップグレードする方法の詳細については、こちらをご覧ください。
詳細解説
レンダリング中にスタイルを挿入し、Reactが非ブロッキング更新を処理している場合、ブラウザはコンポーネントツリーのレンダリング中にフレームごとにスタイルを再計算します。これは非常に遅くなる可能性があります。
useInsertionEffect
は、useLayoutEffect
またはuseEffect
中にスタイルを挿入するよりも優れています。これは、コンポーネントで他のエフェクトが実行されるまでに、<style>
タグが既に挿入されていることを保証するためです。そうでない場合、古いスタイルが原因で、通常のエフェクトにおけるレイアウト計算が間違ってしまう可能性があります。