120
82

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

useEffect 初回レンダリングで走るな!!!

Last updated at Posted at 2020-10-09

useEffectって初回に走るんですよ、
これが面倒で面倒で....
かつてのcomponentWillmountやらcomponentDidUpdateやらを使ったclassコンポーネントを
functionコンポーネントに置き換えようとすると悲劇が起こりやすいです。。(今朝の話)

デモンストレーション

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

export default function App() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    console.log("初回だけ走るよ〜");
  }, []);

  useEffect(() => {
    console.log("カウントが押されたとき走るよ〜");
  }, [count]);

  return (
    <div>
      <span>{count}回押された</span>
      <button onClick={() => setCount(count + 1)}>カウントアップ!</button>
    </div>
  );
}

ボタンが押されるとcountが1upするよくあるやつです。
2回目に出てくるuseEffectカウントが押された時だけ走って欲しいとします。
しかし、実際にコンソールをみてみると....スクリーンショット 2020-10-09 13.10.28.png

ボタンを一度しか押していないのに、
console.log("カウントが押されたとき走るよ〜");
が二回走ってしまっています。
componentDidUpdateと全く同じ挙動を期待するなら、一手間必要です。

解決作

フラグを持たせます。
この場合は無駄なレンダリングを避けるためuseRefを使うのが適切でしょう。

- import React, { useEffect, useState } from "react";
+ import React, { useEffect, useState, useRef } from "react";

export default function App() {
  const [count, setCount] = useState(0);
+  const renderFlgRef = useRef(false)
  useEffect(() => {
    console.log("初回だけ走るよ〜");
  }, []);

  useEffect(() => {
+    if(renderFlgRef.current) {
      console.log("カウントが押されたとき走るよ〜");
+    } else {
+      renderFlgRef.current = true
+    }
  }, [count]);

  return (
    <div>
      <span>{count}回押された</span>
      <button onClick={() => setCount(count + 1)}>カウントアップ!</button>
    </div>

  );
}

スクリーンショット 2020-10-09 13.19.15.png

ちゃんとカウントアップ時のみ走らせることができました。

毎度フラグを作るのだるい~

useEffectがたくさんあるような場合は、その個数分フラグ処理が必要ですね。
正直面倒なのでカスタムフックにします。

useEffectCustom
// 絶対に初回走るな
import { useEffect, useRef } from "react";

const useEffectCustom = (func, dependencyList) => {
  const fisrtFlgRef = useRef(true);

  useEffect(() => {
    if (!fisrtFlgRef.current) {
      func();
    } else {
      fisrtFlgRef.current = false;
    }
  }, dependencyList);
};

export default useEffectCustom;
index
import React, { useEffect, useState } from "react";
import useEffectCustom from "./useEffectCustom";

export default function App() {
  const [count, setCount] = useState(0);
  useEffect(() => {
    console.log("初回だけ走るよ〜");
  }, []);

  useEffectCustom(() => {
      console.log("カウントが押されたとき走るよ〜");
  }, [count]);

  return (
    <div>
      <span>{count}回押された</span>
      <button onClick={() => setCount(count + 1)}>カウントアップ!</button>
    </div>
  );
}

これで毎度フラグ処理を実装せずに済みます!

参考資料

120
82
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
120
82

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?