本日の記事はuseEffectとuseLayoutEffectフックの違いを初心者様に解説致します。
useLayoutEffectとuseEffectの違い
こちらのフックは、ほぼuseEffectフックと同様の機能を備えております。
唯一の違いとしては全ては実行時のタイミングとなります。
useEffectはコンポーネントのマウント時に非同期で呼び出され、例えばですが状態やPropsの一部を、すぐに実行する必要がないものだったり、またはページに視覚的に影響を与えないものとなります。
データをフェッチする時と同様に、すぐに変更されることはありません。
また、イベントハンドラの設定やモーダルの表示
および非表示
になったときに状態をリセットする場合などとなります。
useLayoutEffect
フックは同期効果があります。
このフックは、DOMにデータを同期的にロードするために使用され、useEffectフックと同じ機能を致します。
状態を更新して同期的に再レンダリングをトリガーする必要がある場合に役立ちます。
ほとんどのニーズにはuseEffectで十分ですが、同期的に実行されるuseLayoutEffectフックについて知っておく必要があります。
それでは簡単な例で比べてみましょう
useLayoutEffect例
まずは、useEffectフックの挙動を任意のブラウザ上に表示してご確認下さい。
// useEffectフック import { useState, useEffect } from 'react'; const App = () =>{ const [count, setCount] = useState(100); useEffect(() => { setCount(0); }, []); return <div>{count}</div>; } export default App;
useEffectフックの場合は、一瞬ですが数字の(100)が表示された後に、0が表示されます。
これは一度、画面に描画された値がuseEffect内の処理が実行される動作となっております。
では、次にこれをuseLayoutEffectフックの場合での挙動を見てみましょう。
//useLayoutEffectフック import { useState, useLayoutEffect } from 'react'; const App = () => { const [count, setCount] = useState(100); useLayoutEffect(() => { setCount(0); }, []); return <div>{count}</div>; } export default App;
useLayoutEffctフックでは画面が描写される前に実行されるので、初期値である(100)が画面に表示されることはなく0が表示されます。
useLayoutEffectフックが同期的に呼び出されるので、コンポーネントがマウントされる前に状態が更新されます。
仮に、コンポーネントが2回レンダリングされたとしても、useLayoutEffectは視覚的に1回だけ更新されます。
そして、エフェクトの実行が終了するまでアプリは視覚的に更新はされずに、ほとんどは実行中に一時停止する必要がない事になります。
useLayoutEffectは同期的であるため、使用する場合は注意が必要となります。
useLayoutEffect内での重い計算は、UI全体を停止させることなく、その処理が完了するまでに描画の変更が行われます。
UIの停止や一時停止は起こらず、他のタスクや処理も続行されます。
つまり、useLayoutEffectは、DOMの更新直後に同期的な計算を行うため、その処理が重い場合やパフォーマンスの問題がある場合には、画面の描画に影響を及ぼす可能性があります。
そのため、できるだけ軽量な計算に留めるか、useEffectを選択することも考慮すべきです。また、useLayoutEffectはサーバーサイドレンダリング(SSR)の際にも問題を引き起こす可能性があるため、その点も注意が必要です。
以上の点を踏まえて、useLayoutEffectとuseEffectを適切に選択し、パフォーマンスや描画の問題を回避しながらアプリケーションを開発することが重要です。
useLayoutEffectはすべてのレンダリングの後、画面が更新される前に実行されることがわかって頂けたかと思います。
そのため、必要に応じて名前の状態値を更新できます。
画面が更新される前に、名前の状態値を変更するためにuseLayoutEffectフックを使用します。
比較を行い、初期状態の値として特定の名前を確認し、名前の状態を他の名前に変更します。
import { useState, useLayoutEffect } from "react"; const App = () => { const [name, setName] = React.useState("dev.K"); useLayoutEffect(() => { if (name === "dev.K") { setName("Taro"); } }, []); return ( <div> <h1>Hello {name}</h1> </div> ); };
See the Pen React useLayoutEffectフック by dev.K | Webアプリ開発者 (@enjinia_f) on CodePen.
画面が更新される前に、名前の状態が更新されていることがわかります。
useLayoutEffectが実行され、初期値である名前は表示される事なく、ブラウザが描画する前に名前の状態が更新されます。
import { useState, useLayoutEffect } from 'react'; const App = () => { const [number, setNumBer] = useState(0); useLayoutEffect(() => { if (number === 0) { setNumBer(10 + Math.random() * 200) } }, [number]) return ( <div> <button onClick={() => setNumBer(0)}> value:{number} </button> </div> ); } export default App;
上記では、ボタンをクリックすると、状態がすぐに変化し0にリセットされます。
コンポーネントが再レンダリングされた後に、エフェクトが実行され値が乱数に設定され、コンポーネントは再度レンダリングされます。
最後に
useLayoutEffectは、DOM要素のスクロールの高さ、スクロールの幅、スクロールの位置、その他のスタイルなどのDOM測定を実行する場合に特に便利です。
正しく使用される限り、useLayoutEffectはパフォーマンスの低下を引き起こすことはありません。
これらフックを使用するときは、useEffectとuseLayoutEffectを適切に使い分けることで、同期と非同期の動作を管理できます。
そして、本当に必要でない限りuseLayoutEffectフックを使用しないことが正しい判断です。
本日は以上となります。
最後までこの記事を読んで頂きありがとうございます。
この記事が役に立ったら、ブックマークと共有をして頂けると幸いです。