React

ReactのEffectとデータ取得

Reactの外にある処理と同期し、API通信を安全に画面へ反映します。

React入門の講座一覧

01

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は、原則として依存配列へ入れます。

02

タイマーとcleanup

Effectで登録した処理は、コンポーネントが画面から外れたときに解除します。解除処理を返す関数をcleanupと呼びます。

時計を更新するJSX
import { useEffect, useState } from 'react';

useEffect(() => {
  const timerId = setInterval(() => {
    setNow(new Date());
  }, 1000);
  return () => clearInterval(timerId);
}, []);
cleanupを忘れない画面へ戻るたびにイベントやタイマーを追加すると、同じ処理が複数回実行されます。登録したものを解除する関数を必ず対応させます。
03

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やリクエスト番号の管理を検討します。

04

Effectの使いすぎを避ける

propsやstateから計算できる値を、別のstateへ保存してEffectで同期する必要はありません。たとえば絞り込み結果はレンダー中にitems.filter(...)で求めます。

Effectを使う判断レンダー中に計算できるか、クリックイベントの処理ではないか、外部システムとの同期が本当に必要かを順番に確認します。

Effectは便利ですが、処理の中心ではありません。まず通常の関数とイベントハンドラーで表現できないか考えると、依存配列の問題を減らせます。