TK-NOTE

技術的なことや趣味、読んだ本についての感想などを投稿してきます。

useEffectについて知る

Cover Image for useEffectについて知る
React

副作用とは何か?

通常のプルグラム処理は引数を与えられて、返却値を返します。
例えば以下のCaluculateTax関数は価格を引数に設定すると、税額を返します。CaluculateTax関数は外部に何も影響を与えることはありません。

function CalculateTax(price) {
  return price * 0.1
}


副作用とは関数の外に影響を与えてしまうことです。DOMを更新したり、APIを実行したり、console.logを出力したり、ファイルに出力したり、状態を更新したりする処理が該当します。

クラスコンポーネントのライフサイクルメソッドとは何か?

クラスコンポーネントでは①componentDidMount、②componentDidUpdate、③componentWillUnmountというライフサイクルメソッドがあります。
componentDidMountはコンポーネントが生成されるときに1回のみ実行される処理を記述します。(例えば初回のAPI実行でデータを取得する処理など)
componentDidUpdateはコンポーネントが更新されるときに実行される処理を記述します。
componentWillUnmountはコンポーネントが破棄されるときに実行される処理を記述します。(例えばAPIの通信切断など)

useEffect とは何か?

useEffectは副作用を実行できる、クラスコンポーネントのライフサイクルメソッドに相当するReact hooksです。
useEffectの第一引数には実行する処理を、第二引数には依存配列を指定します。依存配列に特定の変数を指定した場合はその変数が更新された場合に実行され、空配列を指定した場合は初回のみ実行されます。

useEffect(() => {
  // 実行する処理
}, 依存配列);


クラスコンポーネントでの従来の実装

まず、クラスコンポーネントでの実装を見てみます。
以下の例はクラスコンポーネントでdocument.titleを副作用で変更している例です。

import React, { Component } from "react";

class ClassComponentWithoutUseEffect extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
    };
  }

  componentDidMount() {
    document.title = `Current count is ${this.state.count} !`;
  }

  componentDidUpdate() {
    document.title = `Current count is ${this.state.count} !`;
  }

  render() {
    return (
      <div>
        <p>current count is {this.state.count}</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Count UP
        </button>
      </div>
    );
  }
}

export default ClassComponentWithoutUseEffect;


useEffectを使用しての実装

上記処理を関数コンポーネントで書き換えた例です。クラスコンポーネントでの実装と比べてかなり行数が少なくなったことがわかると思います。

import React, { Component, useEffect, useState } from "react";

function FuncComponentWithUseEffect() {
  const [count, setCount] = useState(0);
  useEffect(() => {
    document.title = `Current count is ${count} !`;
  }, [count]);

  return (
    <div>
      <p>current count is {count}</p>
      <button onClick={() => setCount(count + 1)}>Count UP</button>
    </div>
  );
}

export default FuncComponentWithUseEffect;


useEffectでAPI実行を実装してみた

useEffect内でAPI実行を行う処理を実装してみました。APIのリクエストパラメータとしてTodoのIDをテキストフィールドから設定します。エラー時、ローディング時には専用の表示に切り替わります。

import React, { useEffect, useState } from "react";

function SearchTodo() {
  const [error, setError] = useState(null);
  const [todoId, setTodoId] = useState(1);
  const [todo, setTodo] = useState({});
  const [loading, setLoading] = useState(true);
  const fetchTodo = async () => {
    await fetch(`https://jsonplaceholder.typicode.com/todos/${todoId}`)
      .then(res => res.json())
      .then(
        (result) => {
          setTodo(result);
          setLoading(false);
        },
        (error) => {
          setError(error.message);
          setLoading(false);
        }
      );
  };

  useEffect(() => {
    fetchTodo();
  }, [todoId]);

  return (
    <div>
      <input
        type="text"
        value={todoId}
        onChange={(e) => setTodoId(e.target.value)}
      />
      {error ? (
        <div style={{ color: "red" }}>Error: {error}</div>
      ) : loading ? (
        <h1>loading...</h1>
      ) : (
        <div>{todo.title}</div>
      )}
    </div>
  );
}

export default SearchTodo;