React Hooks useEffectの使い方

React_useeffect

こんにちは、ミナトです。

今回はReact HooksのuseEffectについて解説します。

React Hooks useEffectの基本

useEffectを利用することで、関数コンポーネント内でコンポーネントがマウントされた後や更新された後に副作用を実行することができます。

副作用という言葉は聞き慣れないかもしれませんが、API通信や手動でのDOM変更、ログの出力などが副作用の一例です。

useEffectはクラスコンポーネントのライフサイクルメソッドがまとまったものだと思うと理解しやすいと思います。

  • componentDidMount
  • componentDidUpdate
  • componentWillUnmount

useEffectは初回と更新時にコンポーネントがレンダリングされた後に実行されます。

それでは、実際に実装しながら挙動を確認していきましょう。

React Hooks useEffectの使い方

React Appの作成

まずはReactのアプリを新規作成します。作成方法については以下の記事を参考にしてください。

react_usestate

React Hooks useStateの使い方

2021年8月21日

useStateの実装

まず、srcディレクトリの配下にコンポーネントを作成します。my-app/src/components/use_ effect/Component1.js

useEffectは以下のように実装します。

useEffect(() => {
  // 副作用の処理
});

以下の例では簡単なカウンターを実装しています。初回のマウント時とボタンをクリックし、stateが変更されたタイミングでuseEffectの処理が実行されコンソールにログが出力されます。

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

// How to use useEffect
const Component1 = () => {
  const [count, setCount] = useState(0);

  useEffect(() => {
    console.log(count);
  });

  return (
    <div>
      <button onClick={() => setCount(prevCount => prevCount + 1)}>Count Up {count}</button>
    </div>
  );
};

export default Component1;

App.jsを修正して、Component1.jsを表示します。アプリを起動して動作を確認してみてください。初回レンダリングとボタンクリック時にコンソールにcountの値が表示されます。

import './App.css';
import Component1 from './components/use_effect/Component1';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <Component1 />
      </header>
    </div>
  );
}

export default App;

特定の値が変わっていない場合には副作用の適用をスキップする

useEffectの第二引数に配列形式で変数を渡すとレンダリング時にその変数が変更された場合のみ、副作用が実行されます。

つまり、特定の値が変更されていない場合は副作用の実行をスキップできるということです。

実装して、実際に動作を確認してみましょう。

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

// How to use useEffect
const Component2 = () => {
  const [count, setCount] = useState(0);
  const [value, setValue] = useState('');

  // 最初の読み込みの時だけ(実行からの配列[])
  useEffect(() => {
    console.log('useEffect')
  });

  return (
    <div>
      <button onClick={() => setCount(prevCount => prevCount + 1)}>Count Up {count}</button>
      <input type="text" value={value} onChange={e => setValue(e.target.value)} />
    </div>
  );
};

export default Component2;

上記の例では、countとvalueという二つのstateを定義しています。

countはボタンをクリックした際に変更され、valueはテキストフィールドの値を変更した際に更新されます。

また、useEffect()はコンソールに「useEffect」と表示されるだけの単純な処理です。

App.jsでComponent2.jsを表示し、動作を確認してください。初回レンダリング時、ボタンクリック時、テクストフィールド入力時にuseEffectが実行され、コンソールにログが出力されます。

続いて第二引数をセットして動作を確認してみます。以下のコードを修正してください。

useEffect(() => {
  console.log('useEffect')
}, [value]);

第二引数に配列の形式で値を渡します。今回はvalueを指定します。

今度はvalueに変更があった場合はコンソールにログが出力されますが、ボタンをクリックした場合は、コンソールにログが出力されなくなります。

初回のレンダリング時のみ実行する

続いて初回のレンダリング時のみ副作用を実行する方法を確認します。コードの一部を修正してください。

useEffect(() => {
  console.log('useEffect')
}, []);

第二引数に空の配列[]を渡した場合は、初回のレンダリング時の際にのみ副作用が実行されます。

副作用のクリーンアップ

useEffectではコンポーネントがアンマウントされるときにクリーンアップを定義できます。

クラスコンポーネントにおけるcomponentWillUnmountと同様の処理になります。

それでは実際にクリーンアップ処理を実装していきます。

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

const Timer = () => {
  const [count, setCount] = useState(0);

  const time = () => {
    setCount(prevCount => prevCount + 1);
    console.log('Count up')
  }

  useEffect(() => {
    const  interval = setInterval(time, 1000);
    // clean up
    return () => {
      clearInterval(interval);
      console.log('cleared');
    }
  }, []);


  return (
    <div>
      <h2>{count}</h2>
    </div>
  );
};

export default Timer;

上記の例では、SetIntervalを利用して1秒ごとにcountがカウントアップされるタイマー機能を実装しています。

return () => {
    clearInterval(interval);
    console.log('cleared');
}

useEffect内で関数をリターンすることでコンポーネントのアンマウント時に実行されるクリーンアップ処理を定義できます。

上記の例では、setIntervalでセットしたタイマーをclearIntervalで解除する処理をuseEffectのクリーンアップ処理として定義しています。

import React, {useState} from 'react';
import Timer from './Timer';

const TimerContainer = () => {
  const [display, setDisplay] = useState(true);
  return (
    <div>
      <button onClick={() => setDisplay(!display)} >Switch Timer</button>
      {display && <Timer />}
    </div>
  );
};

export default TimerContainer;

続いてTimerContainer.jsを作成します。こちらでは「Switch Timer」ボタンをクリックした際にdisplayの値(true or false)を変更することでTimerコンポーネントの表示・非表示を切り替えています。

import './App.css';
import TimerContainer from './components/use_effect/TimerContainer';


function App() {
  return (
    <div className="App">
      <header className="App-header">
         <TimerContainer />
      </header>
    </div>
  );
}

export default App;

最後にApp.jsにてTimerContainerコンポーネントを表示します。

実際にアプリを起動し、ボタンを押してTimerコンポーネントがアンマウントされた際にコンソールでクリーンアップ処理が実行されていることを確認してみてください。

まとめ

今回はReact HooksのuseEffectについて紹介しました。以下useEffectのまとめとなります。

まとめ
  • コンポーネントが初回マウントされた後や更新された後に副作用を実行することができる
  • 第二引数に配列で値を指定することで特定の値が更新された場合のみ副作用を実行できる
  • useEffect内で関数をリターンすることでアンマウント時に実行されるクリーンアップ処理を定義できる

最後まで読んでいただき、ありがとうございます。

この記事が、「面白いな」、「勉強になったな」という方は、SNSでシェアしていただけると嬉しいです。