0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[備忘録]useEffectについて理解する②

Posted at

以下の記事の続きです。
[備忘録]UseEffectについて理解する①

UseEffectとは

前回の記事で、なんでuseEffectが必要なのか理解できてきました。
また、レンダリング後にやりたい副作用処理を記述できることを理解しました。
本題のuseEffectについて、もう少し詳しく見ていきます。

基本的な実装は以下です。

import { useEffect } from 'react';

function MyComponent() {
  useEffect(() => {
    // 副作用処理

    return () => {
      // クリーンアップ処理
    };
  }, []); // 依存配列
}

依存配列について

依存配列に、副作用処理の中で使用している状態(state)やプロパティ(props)を指定することで、指定した値が変更されたタイミングで、副作用処理を実行できるようになります。(statepropsと副作用処理を同期できます。)
空の配列を指定した場合は、特に依存する値がないということで、初回レンダリング以降副作用処理が実行されません。

クリーンアップ関数について

コンポーネントが削除されるタイミングで実行され、副作用で行った処理の後始末を行います。

コンポーネントのライフサイクルとEffectの関係

Reactのコンポーネントのライフサイクルには以下の3つのフェーズがあります。

  • マウント(Mount) → コンポーネントが初めて画面に表示される(コンポーネントが DOMに追加される瞬間にマウントされます。)
  • 更新(Update)→ 状態やプロパティが変更される
  • アンマウント(Unmount) → コンポーネントが画面から削除される

それに対して、Effectは、propsstateなどのリアクティブな変数と、副作用との同期の開始と終了のさせ方を決める仕組みを提供しています。

この2つの関係をまとめると、以下のようなよく見る説明になります。

コンポーネントのライフサイクル useEffectの書き方 説明(利用例)
マウント useEffect(() => {...}, []) 初回レンダリング後のみ実行(API取得、イベントリスナー追加などに使う)
更新 useEffect(() => {...}, [変数]) 変数が変わるたびに実行(状態が更新されたときの処理)
アンマウント useEffect(() => { return () => {...}; }, []) コンポーネントが削除される前に実行(イベントリスナー削除、タイマー停止などに使う)

useEffectが無かったら

関数コンポーネントでuseEffectを使った場合と使わなかった場合で何がどう変わるかを見てみます。

以下の例では、Incrementボタンをクリックしてcountstateが更新されるたびに、Counterコンポーネントの再レンダリングが走ります。
また、そのレンダリングの度にuserを取得するためのフェッチが、無駄に走ります。
このように副作用処理をレンダリング中に記載すると、容易に意図しない挙動になります。

import { useState } from "react";

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
  const [count, setCount] = useState(0); // user とは関係ない state

  // count が変わるたびに user取得の API リクエストが走ってしまう
  fetch(`https://xxxxxxxxx/users/${userId}`)
    .then((res) => res.json())
    .then((data) => setUser(data));

  return (
    <div>
      <p>{user ? user.name : "Loading..."}</p>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}
}

今回の場合、userの取得のためのフェッチを初回レンダリング後、または、UserIdが変わったときだけにしたいです。
そのような場合、useEffectを利用することで、こういった副作用処理の問題を解決できます。
以下が修正したコードです。

import { useState, useEffect } from "react";

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
  const [count, setCount] = useState(0); // user に関係ない state

  useEffect(() => {
    fetch(`https://xxxxxxxxx/users/${userId}`)
      .then((res) => res.json())
      .then((data) => setUser(data));
  }, [userId]); // 初回のレンダリングおよび userId が変わったときだけ実行

  return (
    <div>
      <p>{user ? user.name : "Loading..."}</p>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

さいごに

useEffectの超基本でした。
公式ドキュメントには、useEffectの利用方法のアンチパターンも載っていたので、さらにそれも読んで理解を深めたいと思います。

参考

https://ja.react.dev/learn/synchronizing-with-effects
https://ja.react.dev/learn/lifecycle-of-reactive-effects#the-lifecycle-of-an-effect

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?