React の学習を始めている場合、または既にこのライブラリを使用している場合は、特にフックuseEffect
を使用して、非同期関数に関連するエラーまたは警告に遭遇したことがあるはずです。
このフックの機能を学んでいたとき、この関数で return を使用する理由が理解できませんでした。ほとんどの場合、return を使用する必要はなく、React はそれがなくても完全に機能するためです。
React の動作方法とコンポーネントのライフサイクルに慣れるにつれて、多くの場合、特に副作用で、フックuseEffect
で return を使用することが重要すぎることに気付き始めました。
副作用として、リモート サーバーからのデータのフェッチ、ローカル ストレージへの読み取りまたは書き込み、イベント リスナーの設定、サブスクリプションの設定などがあります。これらの副作用は、ボタンがクリックされたとき、フォームが送信されたとき、またはコンポーネントがマウントおよびアンマウントされたときに発生する可能性があります。
React のuseEffect
フックを使用すると、コンポーネントがマウントされたとき、または一部のプロパティや状態が変更されたときに、機能コンポーネントが何かを実行できます。このフックは、コンポーネントがアンマウントされたときのクリーンアップも可能にします。
React での副作用の処理は、中程度の複雑さのタスクです。ただし、コンポーネントのライフサイクル (最初のレンダリング、アセンブリ、使用、分解) と副作用のライフサイクル (開始、進行中、完了) が交差するところで問題が発生することがあります。
そのような問題の 1 つは、副作用が完了し、既に逆アセンブルされたコンポーネントの状態を更新しようとする場合です。
これにより、次のような React 警告が発生します。
React アプリケーションでのメモリ リークは、主に、コンポーネントがアンマウントされる前にコンポーネントがマウントされたときに行われたサブスクリプションをキャンセルしなかったことが原因です。
それらは、次のような多くの問題を引き起こします。
したがって、メモリ リークの問題を解消する必要があります。
コンポーネントがアンマウントされる前に実行する必要がなくなった副作用を停止できるようにするのは、 useEffect
フックの機能です。
useEffect
、その内部で関数を返すことができるように構築されており、この戻り関数でクリーンアップが行われます。
たとえば、コンポーネント A は API に製品のリストを取得するように要求しますが、その非同期要求を行っている間、コンポーネント A は DOM から削除されます (アンマウントされます)。その非同期要求を完了する必要はありません。
したがって、アプリケーションを改善するためのクリーンアップ方法として、非同期リクエストをクリーンアップ (キャンセル) して、完了しないようにすることができます。
useEffect
:
useEffect(() => { // Your effect return () => { // Cleanup } }, [input])
fetch リクエストの呼び出しをキャンセルするにはさまざまな方法があります。fetch AbortController
または Axios AbortController.
AbortController
を使用するには、 AbortController()
コンストラクターを使用してコントローラーを作成する必要があります。次に、フェッチ リクエストが開始されると、リクエストのoptions
オブジェクト内のオプションとしてAbortSignal
を渡します。
これにより、コントローラーとシグナルがフェッチ要求に関連付けられ、 AbortController.abort()
を使用していつでもキャンセルできるようになります。
useEffect(() => { //create a controller let controller = new AbortController(); (async () => { try { const response = await fetch(API, { // connect the controller with the fetch request signal: controller.signal, }, ); // handle success setList(await response.json()); // remove the controller controller = null; } catch (e) { // Handle the error } })(); //aborts the request when the component umounts return () => controller?.abort(); },[]);
useEffect(() => { // create a controller const controller = new AbortController(); axios .get(API, { signal: controller.signal }) .then({data}) => { // handle success setList(data); }) .catch((err) => { // Handle the error }); //aborts the request when the component umounts return () => controller?.abort(); }, []);
setTimeout(callback, time)
タイマー関数を使用する場合、特別なclearTimeout(timerId)
関数を使用してアンマウント時にそれらをクリアできます。
useEffect(() => { let timerId = setTimeout(() => { // do something timerId = null; }, 3000); // cleanup the timmer when component unmout return () => clearTimeout(timerId); }, []);
タイムアウトと同様に、 setIntervals(callback, time)
clearInterval(intervalId)
関数でそれらをクリーンアップする特別な関数があります。
useEffect(() => { let intervalId = setInterval(() => { // do something like update the state }, 1000); // cleanup the timer when component unmout return () => clearInterval(interval); }, []);
リスナーのクリーンアップは、 window.removeEventListener
を介して行われます。 removeEventListener
呼び出しは、リスナーを正しく削除するために、 removeEventListener
呼び出しで同じ関数を参照する必要があります。
useEffect(() => { // function to add to EventListener const handleKeyUp= (event) => { switch (event.key) { case "Escape": setCollapsed(true); break; } } window.addEventListener("keyup", handleKeyUp); // cleanup the listener when component unmout return () => window.removeEventListener("keyup", handleKeyUp); }, []);
を作成するときsocket.close()
関数で閉じることができます。
useEffect(() => { const ws = new WebSocket(url, protocols) // do what you want with the socket ws.onmessage = (event) => { setValue(JSON.parse(event.data)); }; // cleanup the web socket when component unmout return () => ws.close() }, [])
一部の副作用については、メモリ リークや不必要で望ましくない動作を回避するためにクリーンアップが必要であることを学びました。これらの問題を回避し、アプリケーションを最適化するには、 useEffect
フックのクリーンアップ機能をいつ、どのように使用するかを学ぶ必要があります。
コンポーネントがアンマウントされたときに非同期効果をクリーンアップすることをお勧めします。また、非同期の副作用が prop または state の値に依存している場合は、コンポーネントの更新時にそれらをクリーンアップすることも検討してください。
この記事が役に立ち、クリーンアップ機能を正しく使用できるようになったことを願っています。
続きを読む:
ここにも掲載されています。