はじめに
よく技術記事でuseStateが説明されていたり、reactの全般的なもので
const countUp = () => {
setCount(count + 1)
};
みたいな書き方をされているものはありませんか?
自分も以前は恥ずかしながら上記の書き方をしていました。
サンプルコードでは問題がない場合が多いですが以下の不具合が含まれる可能性があります。
どうすればいいの?
結論!!
const countUp = () => {
setCount((prev) => prev + 1)
};
と記述してください。
setCount(count + 1)
でも動くじゃん!と思うかもしれません。
これから理由について説明していきます。
バグが起きるユースケース
import { useState } from 'react'
import './App.css'
function App() {
const [count,setCount] = useState(0)
const handleClick = () => {
setCount(count + 1)
setCount(count + 1)
}
return (
<>
<h1>useState</h1>
<button onClick={handleClick}>count is {count}</button>
</>
)
}
export default App
実際に環境構築したい方は下の記事参考に作ってください
上記のコードぱっと見countボタンを押せば count
が 2ずつ増えるように思えるかもしれません。
しかし実際の挙動は以下のようになります。
countが1ずつしか増えませんよね...
なぜこうなるのか解説していきます。
setCount
は再レンダリングされる直前に実行され、count
は定数
実際に出力してみると分かりやすいかもしれません
const handleClick = () => {
setCount(count + 1)
console.log(count)
}
とすると、実際に出力されるのは初期値が0だとしても0+1
で1と思うかもしれませんが0が出力されます。
更新関数setCount
はstateの次のレンダリングの値とするという指示をするだけで、現時点では初期に設定した0という値が参照されます。
実際に書き出すとこんな感じですね。
import { useState } from 'react'
import './App.css'
function App() {
const [count,setCount] = useState(0)
const handleClick = () => {
setCount(0 + 1)
setCount(0 + 1)
}
return (
<>
<h1>useState</h1>
<button onClick={handleClick}>count is {count}</button>
</>
)
}
export default App
上記を見れば一目瞭然かなと思います!
まとめ
setCount
のような更新関数は即座に実行されるのではなく、再レンダリング前に予約される処理ということ。
count
はあくまで定数ということを意識すれば頭にスッと入るかなと思います。
正しく動いてたとはいえ前記事でsetCount(count + 1)
と書いてたのはすいません
【2023年最新】React(v18)完全入門ガイド|Hooks、Next.js、Redux、TypeScript
本記事は上記のセクション5を参考に作成しました!
Reactを体系的学べてかつ、仕組み自体も図を用いて解説されていて分かりやすいです💪
最後まで読んで頂きありがとうございました!