📝

Pt1. UseEffectの基本的な使い方

2024/07/25に公開

秒数をカウントする関数コンポーネントを作成

import { useState } from 'react';

const Example = () => {
  const [time, setTime] = useState(0);

  window.setInterval(()=>{
    setTime(prev => prev + 1)
  }, 1000); ---> (1)

  return (
    <>
      <h3>
        <time>{time}</time>
        <span>秒経過</span>
      </h3>
    </>
  );
};

export default Example;

(1) 1000ms(=1秒)ごとにsetTime(prev => prev + 1)を実行。

しかし、stateの値を更新すると関数コンポーネントの再レンダリングが実行されるので、画面に表示される秒数はおかしな事になる。

秒数と再レンダリング実行時をコンソールで表示


renderと表記されているタイミングで再レンダリングが行われている。

useEffectを利用する

setInterval関数をuseEffectで囲む。

useEffect(()=>{
    console.log("useEffect!");
    setInterval(()=>{
      setTime(prev => {
        console.log(prev);
        return prev + 1
      })
    }, 1000);
  }
,[]) ---> (2)

(2) 第2引数に空の配列をセットする。

[]の配列をセットすることで最初のレンダリング時のみ、useEffectに登録した関数処理が実行される。
[]を忘れると、(1)の時と同じようにstateが更新されるたびに再レンダリングが実行されてしまう。

最初のレンダリング時のみ、useEffectに登録した関数処理が実行されている。


つまり実行されるsetInterval関数は1回のみ。
今まで変な挙動を起こしていたのはsetInterval関数が何個も登録されていたから。

useEffectの第二引数 => 依存配列

  • 依存配列に time を格納してみる
import { useState, useEffect } from 'react';

const Example = () => {
  const [time, setTime] = useState(0);

  console.log("render");

  useEffect(()=>{
    console.log("useEffect!");
    setInterval(()=>{
      setTime(prev => {
        console.log(prev);
        return prev + 1
      })
    }, 1000);
  },[])

  useEffect(()=>{
    console.log("useEffect has time state!");
  },[time]) ---> (3)

  return (
    <>
      <h3>
        <time>{time}</time>
        <span>秒経過</span>
      </h3>
    </>
  );
};

export default Example;

(3) 第2引数にstateを持つ配列をセットする。

最初のレンダリング時と、秒数(=time)がカウントされていくたびに依存配列timeを持つuseEffectが実行されている。

※useEffectの中で依存配列に格納されている変数をセットしてはいけない!
useEffect(()=>{
    console.log("useEffect has time state!");
    setTime(prev => prev + 1);
},
[time])

依存配列に格納された変数が更新されるたびにuseEffectが呼び出されてしまうので無限ループが発生してしまう。

Discussion