koke TechBlog

主にフロントエンド関係で学んだことを書いていきます。

2021/5/17

[React]useEffectを初回レンダリング時動かないようにする

[React]useEffectを初回レンダリング時動かないようにする

useEffectとは

React hooksの一種。

第一引数に関数を受け取り、その関数をレンダリングが終了した後に実行する。デフォルトではレンダリングされるたびに毎回実行されます。

第二引数に依存するstateやpropsの配列を入れることで実行に条件をつけることが出来る。具合的には、初回レンダリング時か第二引数に入れたstateやpropsの値が更新された時のみ、第一引数の関数を実行します。

const [state, setState] = useState();
useEffect(()=>{
	// レンダリングされるたび実行。
	console.log("render")
})

useEffect(()=>{
	// 初回レンダリング時とstateが更新されたときのみ実行。
	console.log("update state")
}, [state])

したいこと

初回レンダリング時に動かないようにしたい。

例えば、下記のコードを実行したときに、buttonがクリックされstateが1になったときに初めてuseEffectのconsole.logが実行されてほしい。

const [state, setState] = useState(0);
useEffect(()=>{
	// stateに変更があった時だけ動いてほしい!
	console.log(state);
}, [state])
return <button onClick={() => {setState(state + 1)}}>Click</button>

解決法

useRefを使って、初回レンダリング時はreturnするようにする。

useRefはコンポーネントの存在期間中ずっと存在し続ける変数のようなものです。再レンダリングが行われても値がリセットされることはなく、useStateと違い、値を変更しても再レンダリングされることもありません。

import {useRef} from "react"
const Test = () => {
  // refを生成。
	const ref = useRef(0);

	// .currentで値にアクセスできる。
	console.log(ref.current);

	return (
    <div>
      <button
        onClick={() => {
          // .currentの値を更新
          ref.current += 1;
        }}>
				Click
      </button>
      <p>
        {/* buttonをクリックしても表示が更新されない */}
        {ref.current}
      </p>
    </div>
  );
};
}

このような動作をするuseRefを使って、初回レンダリング時のみreturnさせます。

具体的には下記のコードのように、refをtrueで初期化して、初回レンダリング時にref.currentをfalseに変更してreturnさせます。

import { useRef, useEffect, useState } from "react";
const Test = () => {

  // refをtrueで初期化。
  const ref = useRef(true);

  const [state, setState] = useState(0);

  useEffect(() => {
    // 初回レンダリング時はrefをfalseにして、return。
    if (ref.current) {
      ref.current = false;
      return;
    }

    // 2回目以降に実行される。
    console.log(state);
  }, [state]);

  return (
    <button
      onClick={() => {
        console.log("clicked");
        setState(state + 1);
      }}
    >
      Click
    </button>
  );
};

複数のuseEffectを使う場合

複数のuseEffectを使う場合は下のコードのように、一番最後のuseEffectでのみ ref.current = false として、それ以外のuseEffectではreturnだけをします。

useEffect(()=>{
    if(ref.current)return;
    console.log("useEffect 1");
  }, [state])

  useEffect(()=>{
    if(ref.current)return;
    console.log("useEffect 2");
  }, [state])

  // 最後のuseEffectなので、ref.current=falseとする。
  useEffect(() => {
    if (ref.current) {
      ref.current = false;
      return;
    }
    console.log("useEffect 3");
  }, [state])

参考文献

;