勘違いしていたuseStateの挙動
こんにちハ! こんばんハ!
フロントエンドエンジニアとして働いているあんころもちたろうです。
Reactを独学で色々勉強していましたが、たまに躓いたりしました。。。
その躓いた内容を備忘録兼ねて書いていきたいと思います!
stateを更新したのに反映されない・・・
以下のようにstateを更新した後、更新したstateを使いたい時にアレ・・・更新されてない!
ということがありました。
import { useState } from 'react';
const Count = () => {
const [ count, setCount ] = useState(0);
const clickHandler = () => {
setCount(count + 1);
console.log(count);
};
return (
<>
<p>カウント: {count}</p>
<button type="button" onClick={clickHandler}>countup</button>
</>
);
};
count
の初期値を0
にして、ボタンを押したときにclickHandler
関数が実行され、
setCount
関数でcount
の値をcount + 1
にしてます。
当然コンソールに表示されるcountの値は、最初は1
になると思っていたら・・・!
え、0
になっているなんで・・・。
でも<p>カウント: {count}</p>
の箇所は正しく、カウント: 1
となっているし、動作はしているはず。。。
というように私自身陥りました。
まぁそういうものかーと流していたのですが、理解したので備忘録として残したいと思います!
useStateの必要性
そもそもuseState
を使用しないで、記述した場合はどのようになるか見たいと思います。
const Count = () => {
let count = 0;
const clickHandler = () => {
count = count + 1; // count++と同等
console.log(count);
};
return (
<>
<p>カウント: {count}</p>
<button type="button" onClick={clickHandler}>countup</button>
</>
);
};
上記の期待値としては、カウント: 1
やカウント: 2
になることですが、通常の変数の場合だと値が更新されません。
コンソールでは期待していた値が来てます。
内部的にはcount
変数が更新されているのですが、レンダリングされていません。
そこで先ほどのuseState
を使ってみます。
今度はCountコンポーネントがレンダリングされるタイミングを確認します。
import { useState } from 'react';
const Count = () => {
const [ count, setCount ] = useState(0);
console.log(`レンダリングされました。count: ${count}`);
const clickHandler = () => {
setCount(count + 1);
};
return (
<>
<p>カウント: {count}</p>
<button type="button" onClick={clickHandler}>countup</button>
</>
);
};
※ strictモードだとコンソール上に2回出るらしいです。
count
が更新される度にCountコンポーネントがレンダリングされているのが確認できると思います!
setCount
関数が実行されると、再レンダリングするよう依頼します。
依頼するので直後に再レンダリングするのではなく、値の更新と再レンダリングは非同期で実行されます!
非同期で実行されるため、setCount
実行した直後にconsoleでcount
を確認しても値が更新されていないようです。
まとめ
useState
で実行する更新の関数(上記だとsetCount
)は、非同期で値を更新・再レンダリングする。
これを忘れないようにしたいと思います!!
公式ドキュメントをちゃんと読んでいれば躓くことは無かったのかもしれない・・・。
Discussion