1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【React】map内のsetStateが反映されない原因とuseStateの正しい更新方法

Last updated at Posted at 2025-10-09

はじめに

useStateの値を合計にして、一気に計算しようとしたところ、うまく合計の計算ができなかった。

問題

以下のコードを実行した結果totalの値が、NaNになってしまいます。

import { useEffect, useState } from 'react';

function App() {
  // 1〜10 の数値データ
  const arr = [...Array(3).keys()];
  const [total, setTotal] = useState(0);

  useEffect(() => {
    arr.map((record) => {
      setTotal(parseInt(total) + parseInt(record));
    });
  }, []);

  return (
    <div style={{ padding: 16 }}>
      <p>期待値: 55(1〜10 の合計)</p>
      <p>実際のtotal: {total}</p>
    </div>
  );
}

export default App;

これの原因が、map関数とuseStateです。
map関数で、配列分繰り返してstateの値を更新するイメージでした。
しかし、この場合だと値は更新されず、一番最後の値が、setTotalによって更新されて、totalに入ってしまいます。

結論から言うと、「1回のレンダリング中では、stateの“値そのもの”は固定(1回だけ)」と言うことです。

map関数はレンダリング中に繰り返し処理を行ってますが、setTotalに関しては、まだ処理を行わず、全てが終わってから値が更新されるので、一番最後の値が入って更新がされると言うわけです。

解決方法

3つ解決方法がありましたので共有です。

解決方法1 forEach(おすすめしない)

1個目の解決方法はforEachを使うことです。配列と繰り返しといえば!!と言う手法ですね。


- useEffect(() => {
-    arr.map((record) => {
-      setTotal(parseInt(total) + parseInt(record));
-    });
-  }, []);

+  arr.forEach((record) => {
+     setTotal(parseInt(total) + parseInt(record));
+   });

おすすめしない理由としては、ループ回数分のレンダリングが回ってしまうからです。

解決方法2 useStateの中に関数を記載。(おすすめしない)

こちらの仕方がシンプルですね。

- useEffect(() => {
-    arr.map((record) => {
-      setTotal(parseInt(total) + parseInt(record));
-    });
-  }, []);

+   useEffect(() => {
+       arr.map((record) => {
+       setTotal((prev) => prev + record);
+       });
+    }, []);

useStateの中に関数を書くことができます。このやり方だと、最新の値を逐次反映してくれます。ただし開発モードで行なってるとレンダリングが2回行われますので、合計が2倍になります。StrictModeを外せば解決しますが、開発段階で外すのはおすすめしないです。

- <StrictMode>
    <App />
- </StrictMode>

解決方法3 reduceを使う。(おすすめ)

reduce()は、配列を畳むメソッドです。今回は配列の中身を足して、1つの変数にまとめ、それをsetstateで値を設定していきます。

- useEffect(() => {
-    arr.map((record) => {
-      setTotal(parseInt(total) + parseInt(record));
-    });
-  }, []);

+  useEffect(() => {
+  const sum = arr.reduce((acc, record) => acc +
+  parseInt(record), 0);
+  setTotal(sum);
+  }, []);

おわりに

いざ使ってみると忘れていたり、使えないことが多いので備忘録して残しておきます。

#参考
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce

1
0
1

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?