Effectの役割
useEffectは、コンポーネントの表示とReactの外部システムを同期するHookです。ブラウザーAPI、タイマー、イベント購読、ネットワーク通信などに使います。
タイトルを同期するJSX
import { useEffect } from 'react';
function Page({ title }) {
useEffect(() => {
document.title = title;
}, [title]);
return <h1>{title}</h1>;
}依存配列のtitleが変わったときにEffectが再実行されます。Effect内で参照するpropsやstateは、原則として依存配列へ入れます。
タイマーとcleanup
Effectで登録した処理は、コンポーネントが画面から外れたときに解除します。解除処理を返す関数をcleanupと呼びます。
時計を更新するJSX
import { useEffect, useState } from 'react';
useEffect(() => {
const timerId = setInterval(() => {
setNow(new Date());
}, 1000);
return () => clearInterval(timerId);
}, []);cleanupを忘れない画面へ戻るたびにイベントやタイマーを追加すると、同じ処理が複数回実行されます。登録したものを解除する関数を必ず対応させます。
APIを取得する
通信中、成功、失敗を別のstateで管理すると、利用者へ現在の状態を伝えられます。HTTPステータスも確認し、レスポンスがJSONとして読めるかを確認します。
取得処理の骨格JSX
import { useEffect, useState } from 'react';
useEffect(() => {
const controller = new AbortController();
setStatus('loading');
fetch('/api/books', { signal: controller.signal })
.then(response => {
if (response.ok === false) throw new Error('HTTPエラー');
return response.json();
})
.then(data => { setBooks(data); setStatus('success'); })
.catch(error => {
if (error.name !== 'AbortError') { setError(error.message); setStatus('error'); }
});
return () => controller.abort();
}, []);画面状態の例OUTPUT
loading: 読み込み中…
success: 3件の本を表示
error: HTTPエラー検索語やIDで取得対象が変わるなら、依存配列へその値を入れます。古い通信の結果が後から届く問題を避けるため、AbortControllerやリクエスト番号の管理を検討します。
Effectの使いすぎを避ける
propsやstateから計算できる値を、別のstateへ保存してEffectで同期する必要はありません。たとえば絞り込み結果はレンダー中にitems.filter(...)で求めます。
Effectを使う判断レンダー中に計算できるか、クリックイベントの処理ではないか、外部システムとの同期が本当に必要かを順番に確認します。
Effectは便利ですが、処理の中心ではありません。まず通常の関数とイベントハンドラーで表現できないか考えると、依存配列の問題を減らせます。
