useStateのリセットタイミング&保持される使い方

## useState

UI ツリーで見たときに同じ階層にあるが、別の位置にあると別のステートとして扱われる。

UIツリーとは？
<small>ReactがReact DOMで扱いやすいような形にJSXを変形して渡すときの構造である。(以下：　UIツリー)</small>
<div style="display: flex; width: 100%; justify-content: center;">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2656854/9f8675e5-5284-be67-b996-63dd5e6c3e71.png" style="width: 500px; border-radius: 20px; padding: 16px; box-shadow: rgba(100, 100, 111, 0.2) 0px 7px 29px 0px;" />
</div>


### ステートがリセットされるタイミング

1. 要素が削除されるとき
```
import { useState } from 'react';

export default function App() {
  const [showB, setShowB] = useState(true);
  return (
    <div>
      <Counter />
      ## 注目
      {showB && <Counter />} 
      <label>
        <input
          type="checkbox"
          checked={showB}
          onChange={e => {
            setShowB(e.target.checked)
          }}
        />
        Render the second counter
      </label>
    </div>
  );
}

function Counter() {
  const [score, setScore] = useState(0);
  const [hover, setHover] = useState(false);

  let className = 'counter';
  if (hover) {
    className += ' hover';
  }

  return (
    <div
      className={className}
      onPointerEnter={() => setHover(true)}
      onPointerLeave={() => setHover(false)}
    >
      <h1>{score}</h1>
      <button onClick={() => setScore(score + 1)}>
        Add one
      </button>
    </div>
  );
}
```

上記のコードの一部に`{showB && <Counter />}`と書いている部分がある、これは<strong>showB</strong>というステートがあり、そのステートが <strong style="border-bottom: 3px solid red;">True</strong> になると`<Counter />`が生成される。
しかし<strong>showB</strong>が <strong style="border-bottom: 3px solid red;">False</strong> になると`<Counter />`が削除される。その削除されるタイミングでステートがリセットされる。
<p>
    以下参考画像。
</p>
<div style="display: flex; flex-direction: row; width: 100%; justify-content: center; gap: 20px;">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2656854/8b4a96ed-ebbf-e1a3-bb7e-cd35d42b1926.png" style="width: 100px; height: auto; border-radius: 20px; padding: 16px; box-shadow: rgba(100, 100, 111, 0.2) 0px 7px 29px 0px;" />
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2656854/b6c303b4-4cd0-e1ae-0acc-b4efe11b4eb9.png" style="width: 100px; height: auto; border-radius: 20px; padding: 16px; box-shadow: rgba(100, 100, 111, 0.2) 0px 7px 29px 0px;" />
</div>


### 逆にステートが保持される使い方
<p>
    UIツリー上での位置が同じタイミング。
</p>

```
import { useState } from 'react';

export default function App() {
  const [isFancy, setIsFancy] = useState(false);
  if (isFancy) {
    return (
      <div>
        <Counter isFancy={true} />
        <label>
          <input
            type="checkbox"
            checked={isFancy}
            onChange={e => {
              setIsFancy(e.target.checked)
            }}
          />
          Use fancy styling
        </label>
      </div>
    );
  }
  return (
    <div>
      <Counter isFancy={false} />
      <label>
        <input
          type="checkbox"
          checked={isFancy}
          onChange={e => {
            setIsFancy(e.target.checked)
          }}
        />
        Use fancy styling
      </label>
    </div>
  );
}

function Counter({ isFancy }) {
  const [score, setScore] = useState(0);
  const [hover, setHover] = useState(false);

  let className = 'counter';
  if (hover) {
    className += ' hover';
  }
  if (isFancy) {
    className += ' fancy';
  }

  return (
    <div
      className={className}
      onPointerEnter={() => setHover(true)}
      onPointerLeave={() => setHover(false)}
    >
      <h1>{score}</h1>
      <button onClick={() => setScore(score + 1)}>
        Add one
      </button>
    </div>
  );
}
```

<p style="text-align: center;">
上記のコードでinput:checkboxに注目していただくと、2つとも階層が<br /><code>div > label > input</code><br />にあると思います。<br /><br />上記のように同じ階層だとステートの値は保持されます。</p>


## 問題
### Q1. 以下のコードでステートは削除されるか。
```
import { useState } from 'react';

export default function MyComponent() {
  const [counter, setCounter] = useState(0);

  function MyTextField() {
    const [text, setText] = useState('');

    return (
      <input
        value={text}
        onChange={e => setText(e.target.value)}
      />
    );
  }

  return (
    <>
      <MyTextField />
      <button onClick={() => {
        setCounter(counter + 1)
      }}>Clicked {counter} times</button>
    </>
  );
}
```


<details>
  <summary style="padding: 16px; background-color: #ACACAC; border-radius: 16px;">解答を見る</summary>
  <div style="position: relative; top: -16px;padding: 32px 0 16px 16px; background-color: #F5F5F5; z-index: -10; border-radius: 0 0 16px 16px;">ステートは削除される</div>
</details>

### Q2. 以下のコードでステートは別々に扱われるか。
```
import { useState } from 'react';

export default function Scoreboard() {
  const [isPlayerA, setIsPlayerA] = useState(true);
  return (
    <div>
      {isPlayerA &&
        <Counter person="Taylor" />
      }
      {!isPlayerA &&
        <Counter person="Sarah" />
      }
      <button onClick={() => {
        setIsPlayerA(!isPlayerA);
      }}>
        Next player!
      </button>
    </div>
  );
}

function Counter({ person }) {
  const [score, setScore] = useState(0);
  const [hover, setHover] = useState(false);

  let className = 'counter';
  if (hover) {
    className += ' hover';
  }

  return (
    <div
      className={className}
      onPointerEnter={() => setHover(true)}
      onPointerLeave={() => setHover(false)}
    >
      <h1>{person}'s score: {score}</h1>
      <button onClick={() => setScore(score + 1)}>
        Add one
      </button>
    </div>
  );
}
```
<details>
  <summary style="padding: 16px; background-color: #ACACAC; border-radius: 16px;">解答を見る</summary>
  <div style="position: relative; top: -16px;padding: 32px 0 16px 16px; background-color: #F5F5F5; z-index: -10; border-radius: 0 0 16px 16px;">別々に扱われる</div>
</details>