89
47

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 1 year has passed since last update.

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

Posted at

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

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

スクリーンショット 2022-07-25 23.06.07.jpg

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

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

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

image.png

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

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を使ってみたんだがリストは追加されてるんよ」

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

スクリーンショット 2022-07-25 23.11.59.jpg

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

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

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

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

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

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

大吾「ほな、さっきのノブのコード見てみよか」

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

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

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

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

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

  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

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

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

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

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

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

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

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

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

ノブ「おおっ!!追加されとるぞ」

スクリーンショット 2022-07-25 23.43.31.jpg

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

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

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

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

最後に

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

89
47
0

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
89
47

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?