目的
ボタン押下時によるステートの更新処理はたくさん記事にされている。。。
じゃあaddEventListener
を使用した際のステートの扱いについては?って思ったのでまとめてみました。
今回は画面がクリックされた際にカウントを1増やす簡単な処理を実装していきます。
addEventListenerの実装(useEffect)
実装方法自体は単純で、useEffect
を使用します。
useEffectにrender後の処理、つまりaddEventListener
を記述すればOKです。
import React, { useState, useEffect} from "react";
const Count = () => {
const [count, setCount] = useState(0);
useEffect(() => {
// イベントリスナーを登録
window.addEventListener("click", (event) => {
setCount(count => count + 1);
});
}, []);
return (
<div>
<h1>{count}</h1>
</div>
);
};
export default Count;
イベントリスナー内での最新のステート値の利用(useRef)
この記事のタイトルにもあるように、イベントリスナー内でセットされたステート値を使用する際は一工夫必要になります。
問題として、そのままステート値を使おうとしても更新されていない値が取得されてしまいます。
その解決方法としてuseRef
を使います。
import React, { useState, useEffect, useRef } from "react";
const Count = () => {
const [count, setCount] = useState(0);
const countRef = useRef(null); // ref オブジェクト作成する
countRef.current = count; // countを.currentプロパティへ保持する
useEffect(() => {
// イベントリスナーを登録
window.addEventListener("click", (event) => {
setCount(count => count + 1);
console.log(count); // 更新前の値「0」が取得される
console.log(countRef.current); // 更新後の最新のcountの値が取得される
});
}, []);
return (
<div>
<h1>{count}</h1>
</div>
);
};
export default Count;
refオブジェクトの.current
プロパティにステートへの参照を保持することで、常に最新のステート値を取得することが出来るようになります。
まとめ
公式にもあるように、useRef は何もDOM への参照を保持するためだけにあるのではありません。その current プロパティの値は書き換え可能かつどのような値でも保持することができます。
https://ja.reactjs.org/docs/hooks-faq.html#is-there-something-like-instance-variables