Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

ReactのuseStateを使ったstate更新関数に関数を渡したときの変な挙動について知りたい

解決したいこと

破壊的メソッドとミュータブル・イミュータブル [React,Javascript] - Qiita
https://qiita.com/takeiin/items/448d76ba1cd65dbc585a

こちらの記事を参考にしてコードを書きましたところ
配列要素を1つずつ追加しているのに、2つ連続で追加されるという症状が発生しました。

Reactのバグ?とも思えるような変な動作だと感じたのですが、これがなぜ起きるのかを知りたいです。ご存知の 方おられましたら教えてください。

発生している問題・エラー

コードを実行すると

[0,1]
[0,1,1,1]
[0,1,1,1,1,1]

と、はじめの1回はpush(1)されるのですが、次からはpushが2回行われているように値が増えてしまいます。

pushを1回しか行っていないので、1つずつ増えると思ってたのですが、なぜかうまくいきませんでした。

該当するソースコード

import logo from './logo.svg';
import './App.css';
import { useState } from "react";

function App() {
  const [num, setNum] = useState([0]);

  const addNum = () => {
    setNum((preNum) => {
      preNum.push(1);
      console.log({preNum})
      return [...preNum];
    });
  };

  return (
    <>
      <button onClick={addNum}>1増えるよ</button>
      <p>{num}</p>
    </>
  );
}

export default App;

自分で試したこと

望んでいる動作をさせるには次のように記載すればよいことは動作確認してわかっています。

正しく動作させる方法がわからないのではなく、上記のコードでなぜ意図しない push が2回されているような挙動になるかということに疑問があり、その動きを知りたいという質問になります。

  const addNum = () => {
    num.push(1);
    setNum([...num])
  };
  const addNum = () => {
    setNum((preNum) => {
      const newNum = [...preNum];
      newNum.push(1);
      return newNum;
    });
  };
0

1Answer

strict モード – React が有効になっているためだと思います。

... 以下の関数を意図的に 2 回呼び出すことによって行われます。
...

  • state 更新用関数 (setState の第 1 引数として渡されるもの)
    ...
1Like

Comments

  1. うわあ!こんな機能あったのですね!!!

    リンク先の記載でいろいろ問題が解決しました。

    > 補足
    > React 17 以降で、React は console.log() のようなコンソールメソッドを自動的に変更し、ライフサイクル関数の 2 回目のコールでログが表示されないようにします。これにより特定のケースで意図しない動作を引き起こすことがありますが、回避策も存在します。

    大変ありがとうございます。助かりました。

Your answer might help someone💌