はじめに
Reactで開発を行うにあたって外部システムとの同期をエフェクトを通じて行います。
エフェクトの利用はuseEffect
が使われることが多く、次点でuseLayoutEffect
が使われると考えています。そして、CSS in JSのライブラリ開発などではuseInsertionEffect
が利用されます。
この記事ではそれらのエフェクトを利用する3つのhooksについて見ていきます。
useEffect
useEffect
は以下のような型を持ちます。
declare const UNDEFINED_VOID_ONLY: unique symbol;
type Destructor = () => void | { [UNDEFINED_VOID_ONLY]: never };
type EffectCallback = () => void | Destructor;
type DependencyList = readonly unknown[];
function useEffect(effect: EffectCallback, deps?: DependencyList): void;
第1引数はエフェクトの内容を記述する関数です。この関数はコンポーネントがブラウザに初めて描画された後に実行されます。
第2引数はエフェクトの実行タイミングを管理する引数です。第2引数に値を渡さなかった場合はコンポーネントがブラウザに描画されるたびに再実行されます。第2引数に配列を渡した場合は各レンダリング時にその値が変化するたびにブラウザに描画された後に実行されます。空の配列を渡した場合は初回のブラウザへの描画後のみ実行されます。
第1引数の関数の返り値は型の上ではvoidを返すようになっていますが、クリーアップ関数と呼ばれる関数を返すようにも記述できます。この関数は新たなエフェクトが実行される直前に実行されます。実行されるのは新しいエフェクトの内容ではなく、実行されたエフェクトで記述された関数が実行されます(ローカル変数などは実行された時のものをそのまま使います)。
例
ブラウザへの描画が完了されるたびに実行される
useEffect(() => {
console.log(1);
});
ブラウザへの初回描画が完了されるときに実行される
useEffect(() => {
console.log(1);
}, []);
count
の更新後にブラウザへの描画された後に実行される
useEffect(() => {
console.log(1);
}, [count]);
クリーンアップ関数の順番
const Sample = () => {
console.log('レンダリング時に実行される関数');
useEffect(() => {
console.log('ブラウザの描画後に実行される関数');
() => {
console.log('次のエフェクト実行時に実行される関数');
};
});
return <></>;
};
useLayoutEffect
関数の形はuseEffect
と同じですが、useLayoutEffect
はエフェクト関数が描画される前に実行されます。
useInsertionEffect
useInsertionEffect
はuseLayoutEffect
よりも早いタイミングでエフェクトを発火させます。早いタイミングでエフェクトが発火されるので、DOM情報をref
経由で取得しようとしても、初回の実行では取得できていません。
そして、このhooksのエフェクト関数では状態の更新を行えないです。
比較
基本的にはuseEffect
を利用することが推奨されているという前提であることに留意してください。
実行における順番は以下のようになっています。
useInsertionEffect
は基本的にCSS in JSからの動的スタイル注入されるために存在します。useInsertionEffect
というuseLayoutEffect
よりも早く実行されるhooksがあることでランタイム時の注入が間違ったタイミングで行われることよる遅延を防ぐことができます。間違ったタイミングとは他のuseLayoutEffect
の処理と注入のタイミングが同じになることです。
そして、useEffect
とuseLayoutEffect
は実行のタイミングが画面への描画前後という違いを活かして活用されます。基本的にはuseEffect
を利用します。実行されるエフェクトが描画に関わるものであった場合にuseEffect
を使うと画面に描画を行った後にエフェクトを実行して再度描画し直すような動きになるので、画面がチラつくことがあります。そのような場合はuseLayoutEffect
を用いてチラつきを抑制します。