予期しないuseEffectが動いている原因

## 1. 要素の出しわけでrenderが走っている
もし第二引数を空`[]`にしても予期しない`useEffect`が走る場合は、要素が新たに表示されてrenderが走っている可能性あり。
下記のような方法で子コンポーネントが表示、非表示されていないか確認する。
子コンポーネント側でuseEffectを使用している場合に予期しないuseEffectが走る可能性がある。
```tsx
import React, { useState, useEffect } from 'react';

function ParentComponent() {
  const [showChild, setShowChild] = useState(false);

  const handleClick = () => {
    setShowChild(!showChild);
  };

  return (
    <div>
      <button onClick={handleClick}>
        {showChild ? 'Hide Child' : 'Show Child'}
      </button>
      {showChild && <ChildComponent />}
    </div>
  );
}

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

  return <div>This is the child component.</div>;
}
```

## 2. render毎に新しいobjectが作られている
同列のstateが変更した時に、再renderするのだがuseEffectの第二引数がrenderの度に違うobjectとして生成されている。

下記の例だと、ageとnameの値が変わらなかったとしてもrenderの度に新しい`person`としてobjectが生成される。そのため`person`に関係ない`setDarkMode`をした時もuseEffectが走ってしまう。

```tsx
import { useEffect, useState } from "react";
import "./App.css";

function App() {
  const [age, setAge] = useState(0);
  const [name, setName] = useState("");
  const [darkMode, setDarkMode] = useState(false);

  // renderの度に新しいperson objectを生成
  const person = { age, name };

  useEffect(() => {
    // darkModeが変わった時にも呼ばれる
    // personが毎回違うobjectとして認識されるため
    console.log(person);
  }, [person]);

  const appStyle = {
    backgroundColor: darkMode ? "black" : "white",
    color: darkMode ? "white" : "black",
  };

  return (
    <div style={appStyle}>
      <label>Name:</label>
      <input
        type="text"
        value={name}
        onChange={(e) => setName(e.target.value)}
      />
      <br />
      <label htmlFor="age-input">Age:</label>
      <input
        type="number"
        value={age ?? ""}
        onChange={(e) => setAge(e.target.value)}
      />
      <br />
      <label>Dark Mode:</label>
      <input
        type="checkbox"
        checked={darkMode}
        onChange={() => setDarkMode((prev) => !prev)}
      />
    </div>
  );
}

export default App;

```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/380959/b3a86e5a-6195-05b9-88d6-8c4349096df3.png)
上記にて、checkBox押した時に`useEffect`を動かしたくない場合はuseMemoを使って`name`か`age`が変更された時のみ新しいobjectを生成するようにすれば良い。

```tsx
import { useEffect, useState, useMemo } from "react";
import "./App.css";

function App() {
  const [age, setAge] = useState(0);
  const [name, setName] = useState("");
  const [darkMode, setDarkMode] = useState(false);

  // personをuseMemo化することによってageとnameが変わった時のみ新しいobjectを生成するようにする
  const person = useMemo(() => {
    return { age, name };
  }, [age, name]);

  useEffect(() => {
    // darkModeが変わった時に呼ばれなくなる
    // ageとnameが変わった時のみpersonが生成されるため
    console.log(person);
  }, [person]);

  const appStyle = {
    backgroundColor: darkMode ? "black" : "white",
    color: darkMode ? "white" : "black",
  };

  return (
    <div style={appStyle}>
      <label>Name:</label>
      <input
        type="text"
        value={name}
        onChange={(e) => setName(e.target.value)}
      />
      <br />
      <label htmlFor="age-input">Age:</label>
      <input
        type="number"
        value={age ?? ""}
        onChange={(e) => setAge(e.target.value)}
      />
      <br />
      <label>Dark Mode:</label>
      <input
        type="checkbox"
        checked={darkMode}
        onChange={() => setDarkMode((prev) => !prev)}
      />
    </div>
  );
}

export default App;
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/380959/e5a80230-74da-2b91-f270-4fa294f01cf7.png)
チェックボックスを変更しても、useEffectが動かなくなった

[参考ビデオ](https://youtu.be/GGo3MVBFr1A?t=760)