2
1

useStateの値を更新したのに古い値が表示される

Last updated at Posted at 2024-08-04

はじめに

ReactのuseStateを使用した際の処理で引っかかった点があったのでまとめてみようと思います。

事象

以下のようなbuttonがクリックされたら配列の中身を表示する処理があります。
image.png

App.jsx
const [array, setArray] = useState([]);
const [element, setElement] = useState(0);
const onChangeElement = (event) => setElement(event.target.value);
const onClickButton = () => {
  setElement(element);
  const newArray = [...array, element];
  setArray(newArray);
  setElement(0);
  console.log(array);
}

return (
  <>
    <div>
      <input type={"number"} value={element} onChange={onChangeElement} />
    </div>
    <button onClick={onClickButton}>表示</button>
    <p>={JSON.stringify(array)}</p>
  </>
)

1,2,3と入力とそれぞれ入力していけば配列に値が追加されます。
image.png

ここで、console.log(array)の部分はsetArray(newArray);で新しい配列に置き換えているので、新しい配列がconsole.logに表示されると思っていました。
しかし、表示されたのは3を追加する前の古い配列でした。
image.png

以下のように実行しても、同じ結果です。
別の関数consoleLogsShowconsole.log(array);を実行

const [array, setArray] = useState([]);
const [element, setElement] = useState(0);
const onChangeElement = (event) => setElement(event.target.value);
const onClickButton = () => {
  setElement(element);
  const newArray = [...array, element];
  setArray(newArray);
  setElement(0);
  consoleLogsShow();
}

const consoleLogsShow = () => {
  console.log(array);
} 

原因

useStateは非同期に処理を行うため、onClickButtonの関数でconsole.log(array);を行った段階では更新されていないようでした。

gptに聞いてみたら

これは React の状態管理に関する一般的な問題です。console.log の値が変更する前のものになっている理由は、React の useState フックが非同期で動作するためです。setArray や setElement を呼び出しても、その後すぐに console.log で状態を確認すると、まだ更新されていない古い値が表示されることがあります。

ということでした。

追記:上記の情報は間違いみたいでした。
setXX 関数がこの挙動の原因ではないようです。
js の関数のスコープの仕組みを使っているので、onClickButton の内側では、array 変数の中身はタイミングによらず必ず古い値となるみたいです。

コメントくださった方ありがとうございます!

以下、参考

解決策

  • 新しい配列のnewArrayを使うようにする
    これだと古い情報は表示されなくなりますね。
const onClickButton = () => {
  setElement(element);
  const newArray = [...array, element];
  setArray(newArray);
  setElement(0);
  console.log(newArray);
}
  • useEffectを使用する
    arrayが変更されたら処理を実行してくれます。
const onClickButton = () => {
  setElement(element);
  const newArray = [...array, element];
  setArray(newArray);
  setElement(0);
}

useEffect( () => {
  console.log(array)
}, [array])

終わりに

関数内でuseStateの値を使い、別の処理を実行したい場合は注意していきたいと思います。

2
1
2

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
2
1