useEffect でcomponentWillUnmount を再現
React のクラスコンポーネントでは、componentWillUnmount
ライフサイクルメソッドを使用して、コンポーネントがアンマウントされる直前にクリーンアップ処理を実行することができました。しかし、関数コンポーネントではこのメソッドが使えないため、useEffect
Hook を利用して同様の動作を実現します。
useEffect Hook の使い方
useEffect
Hook は、副作用(side effect)を扱うためのフックです。副作用とは、レンダリング以外の処理のことです。例えば、データのフェッチ、サブスクリプションの登録、タイマーの設定などがあります。
useEffect
Hook は以下のように使います:
useEffect(() => {
// 副作用を実行する処理
// ...
// クリーンアップ関数 (オプション)
return () => {
// アンマウント時に実行する処理
// ...
};
}, [依存配列]);
componentWillUnmount のシミュレーション
componentWillUnmount
のような動作を実現するには、useEffect
Hook のクリーンアップ関数を使います。クリーンアップ関数は、コンポーネントがアンマウントされる直前に実行されます。
useEffect(() => {
// コンポーネントのマウント時に実行する処理
// 例えば、イベントリスナーの登録、タイマーの設定など
return () => {
// コンポーネントのアンマウント時に実行する処理
// 例えば、イベントリスナーの解除、タイマーのクリアなど
};
}, []);
依存配列
useEffect
Hook の第2引数である依存配列は、効果の再実行をトリガーする値の配列です。空の配列 []
を指定すると、効果はコンポーネントのマウント時にのみ実行され、アンマウント時にクリーンアップ関数が実行されます。
例:イベントリスナーの登録と解除
useEffect(() => {
const handleClick = () => {
// クリックイベントの処理
};
window.addEventListener('click', handleClick);
return () => {
window.removeEventListener('click', handleClick);
};
}, []);
この例では、コンポーネントのマウント時にクリックイベントリスナーを登録し、アンマウント時にリスナーを解除しています。
import { useEffect } from 'react';
function MyComponent() {
useEffect(() => {
const handleClick = () => {
console.log('Clicked!');
};
// イベントリスナーの登録
window.addEventListener('click', handleClick);
// クリーンアップ関数: イベントリスナーの解除
return () => {
window.removeEventListener('click', handleClick);
};
}, []);
return (
<div>
{/* コンポーネントのレンダリング内容 */}
</div>
);
}
解説
- 依存配列
空の配列[]
を指定することで、効果はコンポーネントのマウント時にのみ実行され、アンマウント時にクリーンアップ関数が実行されます。 - クリーンアップ関数
return
ステートメント内の関数がクリーンアップ関数として機能します。コンポーネントがアンマウントされる直前に、この関数が実行され、window.removeEventListener
を使用してイベントリスナーが解除されます。 - イベントリスナーの登録
useEffect
の中でwindow.addEventListener
を使用して、クリックイベントリスナーを登録します。
タイマーの設定とクリア
import { useEffect, useState } from 'react';
function MyComponent() {
const [count, setCount] = useState(0);
useEffect(() => {
const intervalId = setInterval(() => {
setCount(prevCount => prevCount + 1);
}, 1000);
// クリーンアップ関数: タイマーのクリア
return () => {
clearInterval(intervalId);
};
}, []);
return (
<div>
<p>Count: {count}</p>
</div>
);
}
- クリーンアップ関数
clearInterval
を使用して、タイマーをクリアします。これにより、コンポーネントがアンマウントされる際にタイマーが停止されます。 - タイマーの設定
setInterval
を使用して、1秒ごとにカウントをインクリメントするタイマーを設定します。
import { useEffect, useRef } from 'react';
function MyComponent() {
const isMountedRef = useRef(true);
useEffect(() => {
return () => {
isMountedRef.current = false;
};
}, []);
useEffect(() => {
if (isMountedRef.current) {
// コンポーネントがマウントされている場合のみ実行する処理
// 例えば、イベントリスナーの登録、タイマーの設定など
}
}, []);
return (
<div>
{/* コンポーネントのレンダリング内容 */}
</div>
);
}
- 2つ目の useEffect
isMountedRef.current
を条件として、コンポーネントがマウントされている場合のみ副作用を実行します。 - 最初の useEffect
コンポーネントがアンマウントされる際に、isMountedRef.current
をfalse
に設定します。 - isMountedRef
useRef
Hook を使用して、コンポーネントのマウント状態を保持する参照を作成します。
Custom Hook を利用した抽象化
import { useEffect, useRef } from 'react';
function useUnmountEffect(callback) {
const isMountedRef = useRef(true);
useEffect(() => {
return () => {
isMountedRef.current = false;
};
}, []);
useEffect(() => {
if (isMountedRef.current) {
callback();
}
}, [callback]);
}
function MyComponent() {
useUnmountEffect(() => {
// コンポーネントがアンマウントされる直前に実行する処理
// 例えば、イベントリスナーの解除、タイマーのクリアなど
});
return (
<div>
{/* コンポーネントのレンダリング内容 */}
</div>
);
}
- MyComponent
useUnmountEffect
を使用して、アンマウント時の処理を簡潔に記述できます。 - useUnmountEffect
カスタム Hook を定義し、isMountedRef
を利用してアンマウント時の処理を抽象化します。
javascript reactjs react-hooks