おはこんばんちは、@ちーずです。
アドベントカレンダー4日目、本日のテーマはuseRef
です!!
useRef
とは
useRef
とは、参照を保持するためのhookです。
// 変数名 = useRef(初期値)
const ref = useRef(initialValue)
useRef
はとてもシンプルな設計で、
Refオブジェクト({current: initialValue}
) を生成して、その値をメモ化しているだけです。
値の取り出し、変更は下記のように書きます。
// 設定した値を取り出す
const value = ref.current;
// 値を変更する
const ref.current = 2;
つまり、ref.current
の値を変更させているだけなので
再レンダリングが走らないです。
これが、useRef
の最大の特徴です。
▼ 参考
useRef
の活用術
DOMに対する参照
圧倒的にこの使われ方が多いuseRef
ですが、
HTML要素にref
という属性でuseRef
の値を渡してあげることで参照できます。
// useRefの型
// interface MutableRefObject<T> {
// current: T;
// }
// function useRef<T>(initialValue: T): MutableRefObject<T>;
export const InputComponent = () => {
const inputElement = useRef<HTMLInputElement>(null)
return <input ref={inputElement}/>
}
これだけで、
inputElement.current.focus()
でフォーカスさせたり、
inputElement.current.offsetHeight
で高さを取得したりすることができます。
値に対する参照
9割くらいDOMの参照として使われているイメージですが、値に対して使うケースもあります。
一回のみ実行したい
再レンダリングが発生しない点を利用して、
一回のみ実行したい処理があった時の制御でuseRef
を使うことができます。
const once = useRef(true);
useEffect(() => {
if (!once.current) return;
// 実行したい処理
once.current = false;
}, [])
useState
の前の値を保持する
公式ドキュメントにも記載がありますが、前の値を保持する時にuseRef
を使います。
const [count, setCount] = useState(0);
const prevCountRef = useRef();
useEffect(() => {
prevCountRef.current = count;
});
const prevCount = prevCountRef.current;
どのような仕組みで前の値が保持されているかは、下記の記事にてとてもわかりやすく説明されていたため、参考にしてください。
▼ 参考
useRef
の注意点
useEffect
の第二引数にいれても、変更を検知しない
今までの話を通して、「そりゃそうだろ!!」 と思うかもしれませんが
たとえ第二引数にref.current
を書いたとしても、
再レンダリングが起きないため、値が変更しても検知できません。
export const InputComponent = () => {
const inputElement = useRef<HTMLInputElement>(null)
useEffect(() => {
if(inputElement.current) {
// 実行したい処理
}
}, [inputElement.current]);
return <input ref={inputElement}/>
}
しかし、初期状態でマウントされておらず、nullになり続けてしまうケースもあるでしょう。
そのような時は、コールバックRefが使えるかもしれません。
(自分は使ったことがいまのところないです。)
以上、「useRefの基本的な使い方と活用術」でした!