ノブ「配列のstateが上手く更新できんのじゃ！」

## とある開発会社での千鳥の会話

大吾「おおノブ、このまえ頼んだリストの追加機能は完成しそか！？」
ノブ「UIは完成したから、残りはロジックを入れれば完成じゃ」
大吾「UIはどんなもんになっとる！？」
ノブ「こんな感じじゃ。」

![スクリーンショット 2022-07-25 23.06.07.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/85c2a17c-e45f-647a-e1ef-b15b2cd1d9f0.jpeg)


大吾「これじゃこれじゃ！！」
大吾「あとは追加ボタンを押したときにリストが追加されれば完成じゃ！」
ノブ「まあ任せとき。5分もあれば終わる」
ノブ「ちなみに、こんなもん何に使うんじゃ？」
大吾「まあまあ、そこは一旦おいとこうや」

カタカタカタカタカタカタカタカタカタカタカタカタ

ノブ「**配列のstateが上手く更新できんのじゃ！**」

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/7b052c7a-f8dc-bfd2-bfc2-243091666880.png)

大吾「おおっっっ！？。ちょっとノブの書いたコード見せてくれんか」
ノブ「これじゃ。何が悪いのか全くわからん」

```js
const List: NextPage = () => {
  const [list, setList] = useState<string[]>(["リスト"]);

  const addValue = () => {
    list.push("リスト");
    setList(list);
  };

  return (
    <Container>
      <div className="todo-list">
        <div className="input-container">
          <button onClick={addValue}>リストを追加</button>
        </div>
        <ul>
          {list.map((i, index) => (
            <li key={index}>{i}</li>
          ))}
        </ul>
      </div>
    </Container>
  );
};
```

大吾「ほうほう。なるほどなるほど」
ノブ「試しに追加ボタンを押したところで```console.log```を使ってみたんだがリストは追加されてるんよ」

```js
  const addValue = () => {
    list.push("リスト");
    console.log(list);
    setList(list);
  };
```

![スクリーンショット 2022-07-25 23.11.59.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/37def990-a76d-d04a-aa9a-8b89e06168b4.jpeg)

ノブ「何回試してもstateに反映されん（泣）」
大吾「分かった！！！」

## オブジェクトを更新する際は新しい値を入れんとあかん

大吾「オブジェクトを更新する際は新しい値を入れんとあかん」

大吾「Reactフックの```useState```における更新関数にはな、現在の``state``とは異なる値を渡さんといけんのじゃ」
ノブ「どういうことじゃ！？」

大吾「Reactの公式ドキュメントを見てみよか」

https://ja.reactjs.org/docs/hooks-reference.html#bailing-out-of-a-state-update


> 現在値と同じ値で更新を行った場合、React は子のレンダーや副作用の実行を回避して処理を終了します（React は Object.is による比較アルゴリズムを使用します）。


大吾「ほな、さっきのノブのコード見てみよか」
```js
  const [list, setList] = useState<string[]>(["リスト"]);

  const addValue = () => {
    list.push("リスト");
    setList(list);
  };
```

大吾「これだとな。``list.push("リスト");``をしても``push``が破壊的メソットなので```useState```で定義されている```list```の値と同じ値になってしまってるんよ」

大吾「破壊的メソットが分からなかったら、この記事を確認してみてくれ」

https://zenn.dev/tk4/articles/4ccd85460bb3fff7fff8

大吾「試しに```console.log```で見てみよか」
大吾「分かりやすいように新しく変数```newList```を定義して、``list``を直接代入して```push```を使ってみてくれんか」
ノブ「なるほどぉ」

```js
  const [list, setList] = useState<string[]>(["リスト"]);

  const addValue = () => {
    const newList = list;
    list.push("リスト"); // 現在のstateを破壊的に変えている
    console.log(newList === list); // 結果、同じ値になりtrueと判定
    setList(list); // 同じ値を更新しても再描画が起きない
  };
```

![スクリーンショット 2022-07-25 23.22.01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/3d371464-477f-9380-96fe-ec73a0be2cf2.jpeg)


ノブ「おおっ！ ``true``と表示されたぞ」
ノブ「つまり```state```で定義した```list```に直接```push```で値を追加してもと同じ値とみなされてしまうんか」
ノブ「結果として更新関数をstateの更新がされず再描画起きないということじゃな」
大吾「そうじゃ」
ノブ「じゃあ一体どうすれば変わるんか！？」

大吾「スプレット演算子を使うんじゃ」

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Spread_syntax

大吾「スプレット演算子で現在の```state```をコピーして、そのコピーに新しい要素を```push```して更新関数に入れるんじゃ」

大吾「まずスプレット構文で取ったコピーが異なる配列になっているか確認してみよか。」

```js
    const addValue = () => {
    const copy = [...list];
    console.log(copy === list); // falseと表示される
  };
```

ノブ「おおっ！！```false```と出力されたぞ」
ノブ「つまりスプレット構文を使ってコピーを取れば違うオブジェクトになるわけじゃな」
ノブ「じゃあ、コピーした配列にpushで値を追加して更新関数を使えばいいわけか」

```js
  const [list, setList] = useState<string[]>(["リスト"]);

  const addValue = () => {
    const copy = [...list];
    copy.push("リスト");
    setList(copy);
  };
```
ノブ「おおっ！！追加されとるぞ」

![スクリーンショット 2022-07-25 23.43.31.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/22f71c05-f185-2e65-a0d6-73dddcd58f8b.jpeg)

大吾「ちなみに、この書き方でも同じことをしてるから覚えとき」

``` js
  const [list, setList] = useState<string[]>(["リスト"]);

  const addValue = () => {
    setList([...list, "リスト"]);
  };
```

ノブ「ほな、これで実装完了じゃ。感謝せぇ」
大吾「ほぼワシの手柄やないかい！！」


## 最後に

大吾「他にも数多の記事を書いてるから読んでくれぇぇぇぇぇ」

https://qiita.com/KNR109/items/201c133d6eeaabf675a7

https://qiita.com/KNR109/items/7cf6b24bed318dab5715

https://qiita.com/KNR109/items/e50c981e0518141be28f