Reactのフックは、関数コンポーネントに強力な機能と柔軟性をもたらしています。この中でも、useEffect
は、サイドエフェクトを扱うための中心的な存在です。この記事では、useEffect
の基本的な使い方から、実際のユースケースを交えてその力を探っていきます。
サイドエフェクトとは?
- Reactにおける「サイドエフェクト」とは、コンポーネントのレンダリング以外の処理や相互作用のことを指します。具体的には、データの取得、API通信、イベントリスナーの設定、タイマーの処理、DOMの変更などがサイドエフェクトの例です
- Reactコンポーネントは、プロパティ(props)や状態(state)の変化に応じて再レンダリングされます。しかし、コンポーネントのレンダリングだけではなく、アプリケーションの動作に必要な外部の処理や相互作用も存在します。これらの処理や相互作用は、コンポーネントの外部に影響を与えるため、「サイドエフェクト」と呼ばれます。
useEffectの基本
Reactのコンポーネントは再レンダリングが行われると、その内容が更新されます。しかし、データの取得やDOMの直接操作といったサイドエフェクトを扱いたい場合、useEffect
というフックを使用します。
基本的な形は以下のとおりです。
useEffect(() => {
// サイドエフェクトを実行する処理
});
依存配列: 再実行のトリガー
useEffect
はオプションで第二引数として依存配列を受け取ることができます。この配列に指定された変数が変更されると、useEffect
内の関数が再実行されます。
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `カウント: ${count}`;
}, [count]);
ユースケース
いくつかuseEffectが使用されるケースを確認してみましょう。
データの取得
多くのWebアプリケーションは外部APIからデータを取得する必要があります。これはuseEffect
を使用して簡単に実現できます。
const [data, setData] = useState(null);
useEffect(() => {
fetch('/api/data')
.then(response => response.json())
.then(result => setData(result));
}, []);
イベントリスナの追加とクリーンアップ
ブラウザのイベントリスナのようなサイドエフェクトを扱う場合、コンポーネントがアンマウントされる際に追加していたリスナをクリーンアップ(掃除、つまり削除)する必要があります。これもuseEffect
を利用して行います。
useEffect
内でreturn
を使用するとクリーンアップ関数として処理を定義することができます。実行されるのは、次のタイミングです。
- その
useEffect
が再度実行される前 - そして、コンポーネントがアンマウントされるとき
useEffect(() => {
const handleResize = () => {
console.log(window.innerWidth);
};
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
}, []);
なんでクリーンアップが必要なの?
- 意図しない形で追加したイベント(処理)が残ってしまう可能性があります
- そのため、メモリリークや他の不具合の原因となる可能性があります
ローカルストレージの利用
ユーザーの設定やテーマのような情報をローカルストレージに保存する場合、useEffect
を使ってその変更を監視することができます。
const [theme, setTheme] = useState(localStorage.getItem("theme") || "light");
useEffect(() => {
localStorage.setItem("theme", theme);
}, [theme]);
注意点とベストプラクティス
非同期処理を扱う際には、クリーンアップ関数を使用して未解決のプロミスやサブスクリプションをキャンセルすることを忘れないようにしましょう。
無限ループを引き起こす可能性があるため、依存配列を適切に設定することが重要です。
まとめ
useEffect
は、Reactアプリケーションにおけるサイドエフェクトの管理を助ける強力なフックです。これを効果的に使用することで、データ取得やDOMの操作、リソースのクリーンアップなど、多くの一般的なタスクを簡単に処理することができます。正しく使用することで、アプリケーションはさらに強力で効率的になるでしょう。