React のフックで最初につまづいたのが useRef でした(そして今なおつまずき続けています)。なんとなく DOM 操作したときに使ったような…くらいのイメージしかないので、今回は気合を入れて useRef
について調べていきます。
▼ React の基本を復習したい方はこちらもご覧ください
useRef とは
公式ドキュメント を参考にすると、ref を使うケースとしては
- コンポーネントに何か値を記憶させたい
- だけど記憶させている値が変化しても再レンダリングを起こしたくない(無限ループになってしまう場合など)
という場面です。1 は state でも実現できますが、2 は state だとできません。state を変更するためには state setter function が必要であり、state setter function の実行をトリガーとして React は再レンダリングを行うためです。
▼ state についてはこちらもご覧ください
ref.current
の形で current というオブジェクトを使うことができます。
import { useRef } from 'react';
export default function Counter() {
let ref = useRef(0);
function handleClick() {
ref.current = ref.current + 1;
alert('You clicked ' + ref.current + ' times!');
}
return (
<button onClick={handleClick}>
Click me!
</button>
);
}
current は読み取りと書き込みが可能です。書き込み可能ということは state setter function のような特別な関数は必要ありません。
またReact からは追跡されません = レンダリングは起こりません。
state と ref の使い分け、ref を使うタイミング
大きな性質の違いはレンダリングの有無です。
つまり state は画面上に表示されており画面上で更新されてほしい値、ref は画面上で更新の必要がない値に使うのがいいでしょう。
また DOM 操作で使うことも多いでしょう。
DOM 操作における useRef の使い方
React ビルトインで入っていない動作を行わせる場合は ref が必要になってくることがあります。
ここでは 公式ドキュメント から一例を引用します。
import { useRef } from 'react';
export default function Form() {
const inputRef = useRef(null);
function handleClick() {
inputRef.current.focus();
}
return (
<>
<input ref={inputRef} />
<button onClick={handleClick}>
Focus the input
</button>
</>
);
}
// 引用: https://beta.reactjs.org/learn/manipulating-the-dom-with-refs
公式ドキュメント で実際に試してみてほしいのですが、ボタンを押すと input タグがフォーカスされるようになっています。
最初 inputRef.current
に代入されているのは null です。
React が jsx をもとに input タグを作成したとき、 input に対する参照が inputRef.current
に入ります。
よってイベントハンドラ関数 handleClick
の内部に書かれている処理 inputRef.current.focus()
は input.focus()
となります。よって無関係のボタンから input を操作することができるのです。
実装したことがある例として、私は確か「ボタンを押すと input タグに働きかけて画像をアップロードできるようにする」という操作で ref を使いました。このケースとよく似ていますね。
まとめ
-
ref
はstate
と同じように、レンダリングされても消えないように値を記憶することができる -
ref
に保存した値が変更されたことによるレンダリングは起こらない -
ref.current
の形でcurrent
というオブジェクトを使うことができ、ここに保存されたデータの読み取りと書き込みができる - 値は保存したいがレンダリングには影響させたくない場合や、無関係の要素にアクセスする DOM 操作を行う場合に有用