React の useEffect フックの使い方を具体例をまじえて解説【 TypeScript 】

ショウヘイ

どうも、ノマドクリエイターのショウヘイ(@shohei_creator)です。

ふーちゃん

ブログアシスタントのふーちゃんです。

React を使ってアプリを作っていると、「 state や props に変更があった時に、毎回 特定の関数を実行させたい」という場面に遭遇するでしょう。たとえば、『入力フォームの内容を取得して、リアルタイムで別領域にデータを表示させたい』などです。

React には、 state や props などの変化があった時に、任意の処理を実行させられる useEffect フックという機能が用意されています。

この記事では、 React の useEffect フックの構文と具体例について説明します。

目次

React の useEffect フックの概要と実行タイミング

React には、ライフサイクルという概念があります。このライフサイクルは、 React によって DOM ノード(いわゆるコンポーネント)が生成されてから破壊されるまでの各段階によって構成されています。

React のライフサイクルでは、 DOM ノード が生成されて DOM ツリーに追加された状態をマウントした( componentDidMount ))と呼びます。平たくいえば、ブラウザ上の描写に変更が起きた状態です。

ショウヘイ

「マウントした」時点をキッカケにして、特定の処理を実行できる機能こそ、 useEffect フックです。

ふーちゃん

下の引用は、 React のライフサイクルを図にしたものです。

「マウント時」列の最も下にある「 componentDidMount 」のところで、 useEffet フックが起動しますよ!

React のライフサイクル図

React lifecycle methods diagram

React の useEffect フックの基本構文

React の useEffect フックは、コンポーネントの中で使います。また、使う時には、 2 つの引数を設定します。

useEffect フックの第 1 引数には、実行したい関数を設定します。関数の書き方は、アロー関数でも構いません。 useEffect フックの第 2 引数には、 useEffect フックの起動を制御するために監視したい変数を要素として持つ配列を設定します。

こちらは、 JavaScript で useEffect を書いた場合のコードです。ちなみに、 TypeScript で書いた場合でも、基本構文は大差ないです。

import React, { useEffect } from "react";

export const Component = () => {

  useEffect(

    // 実行したい関数
    () => {
      (省略)
    },

    // 変更を監視したい変数を要素に持つ配列
    [var1, var2, var3]
  );

  (以下、省略)
};
ショウヘイ

実際に useEffect フックを使う時は、 react ライブラリから import することを忘れないでください。

import React, { useEffect } from "react";

React の useEffect フックの第 2 引数の役割 

React は、 state や props の変更が起きるたびに、マウント処理を実行します。 DOM の上書き対象のコンポーネントの中で useEffect が使われていた場合は、マウントのたびに useEffect フックも起動することになります。これでは、必要以上に useEffect が起動してしまって不便です。

そこで、 useEffect フックの第 2 引数に設定する配列の出番です。 第 2 引数の配列の要素として変数を設定すると、その変数に変更があった場合にのみ、 useEffect フックが起動する(第 1 引数の関数が実行される)ようになります。

ふーちゃん

useEffect フックの第 2 引数の配列を適切に設定することで、想定外の挙動を防げますね!

ショウヘイ

 第 2 引数の配列は、必ずしも要素を持たせる必要はないんだ。

場合によっては、空の配列のまま設定してもいい。

ふーちゃん

どんな場面で使い分ければいいですか?

ショウヘイ

じゃあ、配列に『要素を持たせる場合』と『要素を持たせない場合』の具体例を載せてみようか。

React の useEffect フックを特定の変数の更新時に起動(第 2 引数の配列に要素を持たせる)

React の useEffect フックの第 2 引数の配列が要素を持っていると、その要素である変数に変更があった場合にのみ、 useEffect フックが起動するようになります。

具体例として、 2 つのカウンターを作りました。カウンターのボタンをクリックすると、 count 変数の値が更新されて、 useEffect フックが起動します。そして、コンソールに「カウンター●のボタンがクリックされました」という文章を出力する仕様です。

たとえば、カウンター 1 のボタンをクリックしても、カウンター 2 の useEffect フック内にある console.log は実行されません。カウンター 2 の useEffect フックの第 2 引数( count2 )は同じままなので、 useEffect フックが起動しないからです。

はじめてブラウザ表示される(初回マウント)時は、 useEffect フックの第 2 引数に関係なく、必ず useEffect フックが起動します。

import React, { useState, useEffect } from "react";
import { Container, Row, Alert, Button } from "react-bootstrap";

export const Counters: React.VFC = () => {
  const [count1, setCount1] = useState<number>(0);
  const [count2, setCount2] = useState<number>(0);

  useEffect(() => {
    console.log("カウンター1のボタンがクリックされました");
  }, [count1]);

  useEffect(() => {
    console.log("カウンター2のボタンがクリックされました");
  }, [count2]);

  return (
    <Container className="mt-4">
      <Row>
        <Alert variant="primary">
          <p>カウンター1: {count1}</p>
          <Button
            variant="primary"
            onClick={() => setCount1((prevCount) => prevCount + 1)}
          >
            カウントを増やす
          </Button>
        </Alert>
      </Row>
      <Row>
        <Alert variant="success">
          <p>カウンター2: {count2}</p>
          <Button
            variant="success"
            onClick={() => setCount2((prevCount) => prevCount + 1)}
          >
            カウントを増やす
          </Button>
        </Alert>
      </Row>
    </Container>
  );
};

React の useEffect フックを初回だけ起動(第 2 引数を空配列にする)

React の useEffect フックの第 2 引数を空配列にした場合は、はじめてブラウザ表示される(初回マウント)時のみ、 useEffect フックが起動します。その後は、 state や props などが更新されて再マウントされることがあっても、 useEffect フックは起動しません。

具体例として、ボタンをクリックするたびに数値が増えるカウンターを作りました。 useState フックによって state が更新されることで、カウンターの数値が増えます。 useEffect フックの関数には、 コンソールに「マウントされました」と出力する ための console.log メソッドを用意しています。

useEffect フックの第 2 引数は、空配列になっています。はじめてブラウザ表示された時は、 コンソールに「マウントされました」と出力されます。その後は、カウンターの数値が増える(再マウントされる)ことがあっても、 useEffect フックが起動しないことが確認できます。

import React, { useState, useEffect } from "react";
import { Container, Alert, Button } from "react-bootstrap";

export const Counter: React.VFC = () => {
  const [count, setCount] = useState<number>(0);

  useEffect(() => {
    console.log("マウントされました");
  }, []);

  return (
    <Container className="mt-4">
      <Alert variant="primary">
        <p>カウンター: {count}</p>
        <Button
          variant="primary"
          onClick={() => setCount((prevCount) => prevCount + 1)}
        >
          カウントを増やす
        </Button>
      </Alert>
    </Container>
  );
};
この記事を知り合いに共有する
URLをコピーする
URLをコピーしました!
目次
閉じる