🙆

useEffectについて

2024/08/02に公開

useEffectについて

今回はuseEffectについて書いていきたいと思います。

useEffectとは

useEffectは、コンポーネントを外部システムと同期させるためのReactフック。
useEffect(setup, dependencies?)
setup:ロジックの関数。
dependencies:setup コード内で参照されるすべてのリアクティブな値のリストで、props、state、コンポーネント本体に直接宣言されたすべての変数および関数が含まれます。空の場合もあり。
dependenciesが空の時、初回レンダリングのみsetupが実行されます。
また、dependenciesに値がある場合は、その値が変化した時setup関数が実行されます。
https://ja.react.dev/reference/react/useEffect

useEffectの注意点

基本的にuseEffectを使用するのは外部システムと同期する必要がある時にしましょう。

外部システムとは

  • ネットワーク
  • 何らかのブラウザAPI
  • サードパーティライブラリ

Reactに制御されていないシステムのことを指します。

不要なエフェクト

  • レンダーのためのデータ変換にエフェクト
function Form() {
  const [firstName, setFirstName] = useState('Taylor');
  const [lastName, setLastName] = useState('Swift');

  // 🔴 Avoid: redundant state and unnecessary Effect
  const [fullName, setFullName] = useState('');
  useEffect(() => {
    setFullName(firstName + ' ' + lastName);
  }, [firstName, lastName]);
  // ...
}

firstNameかlastNameが変更されると、fullNameを更新する必要があるためロジックに名前をくっつける処理、依存配列にfirstName,lastNameと書きたくなります。
しかし、既存のpropsやstateで計算できるものはstateに入れない方がいいです。

function Form() {
  const [firstName, setFirstName] = useState('Taylor');
  const [lastName, setLastName] = useState('Swift');
  // ✅ Good: calculated during rendering
  const fullName = firstName + ' ' + lastName;
  // ...
}

レンダー中に計算することで、コードが高速かつ可読性も上がりました。

  • ユーザイベントの処理にエフェクト

2つのボタン(BuyとCheckout)がある商品ページがあり、どちらのボタンでもその商品を購入できるとします。ユーザが商品をカートに入れるたびに通知を表示したいとします。両方のボタンのクリックハンドラで showNotification()を呼び出すのは繰り返しに感じられるため、エフェクトにこのロジックを配置したくなるかもしれません。

function ProductPage({ product, addToCart }) {
  // 🔴 Avoid: Event-specific logic inside an Effect
  useEffect(() => {
    if (product.isInCart) {
      showNotification(`Added ${product.name} to the shopping cart!`);
    }
  }, [product]);

  function handleBuyClick() {
    addToCart(product);
  }

  function handleCheckoutClick() {
    addToCart(product);
    navigateTo('/checkout');
  }
  // ...
}

このエフェクトは不要です。
例えば、アプリがページのリロード間でショッピングカートを「覚えている」としましょう。一度商品をカートに追加してページを更新すると、通知が再び表示されます。商品ページを更新するたびに通知が表示され続けます。これは、ページの読み込み時にproduct.isInCartがすでにtrueになっているため、上記のエフェクトが showNotification()を呼び出すからです。

  • 正しい書き方
function ProductPage({ product, addToCart }) {
  // ✅ Good: Event-specific logic is called from event handlers
  function buyProduct() {
    addToCart(product);
    showNotification(`Added ${product.name} to the shopping cart!`);
  }

  function handleBuyClick() {
    buyProduct();
  }

  function handleCheckoutClick() {
    buyProduct();
    navigateTo('/checkout');
  }
  // ...
}

まとめ

今回はuseEffectの概要と、注意点やアンチパターンを書きました。
React18からstrict modeをオンにしているとuseEffectも2回発火されるようになるため開発環境で色々なエラーが発生するみたいなので原因や治し方、トラブルシューティングを次回は書きたいなと思います。

Discussion