はじめに
関数コンポーネントのイベントリスナー内で、State(ステート/状態)
が正しく扱えない場合の対処方法です。
React.useState()
のステートを、イベントリスナーのコールバック関数内で参照しようとすると、値が最新の状態になっていないことがあります。
うまくいかない例
counter
というState
を宣言- ボタンをクリックすると
counter
に+1
- クリックに反応したイベントリスナーが
func()
を発火 counter
の値を出力
関数コンポーネント
// ①
const [counter, setCounter] = React.useState(0);
// ④
const func = () => {
console.log(counter);
};
// ③
React.useEffect(() => {
window.addEventListener("click", func);
}, []);
// ②
return (
<button onClick={() => setCounter(counter + 1)}>
ボタン
</button>
この例では、④ console.log(counter)
で出力される値は常に0
です。
イベントリスナーの登録時点のcounter
の値で固定されてしまい、ステートが更新されても出力は変わりません。
これでは何回クリックしたかわからない…。
useRef()を使う
React.useRef()
を使うことで、常に最新の状態を参照することができます。
うまくいく例
const [counter, setCounter] = React.useState(0);
// 追加
const counterRef = useRef(); // refオブジェクトを作成
counterRef.current = counter; // refはcounterを参照する
const func = () => {
// refを出力する
console.log(counterRef.current);
};
// -----以下は変更なし-----
React.useEffect(() => {
window.addEventListener("click", func);
}, []);
return (
<button onClick={() => setCounter(counter + 1)}>
ボタン
</button>
コールバック内でcounter
を使うかわりに、counterRef.current
を使用します。
このようにすることで、最新のステートを参照することができます。
まとめ
関数コンポーネントのイベントリスナー内で、最新のstate
が参照できない場合は、コールバック内でState
を使うかわりに、State
を参照するRef
を使用します。
このようにすることで、最新のステートを参照することができます。