こんにちは。
野中やすおです。
今回の記事では、React.jsが提供する機能であるrefについて勉強がてらまとめています。
refとは何か
refとはrenderメソッドで作成されたDOMノードもしくはReact要素の参照を保持するオブジェクトのことです。refオブジェクトは、次に紹介するuseRefによって具体的に生成されます。
useRefとは何か
useRefは、React Hooks(フック)1つで、refオブジェクトを生成し再レンダリングを発生させずに値を保持する方法です。再レンダリングを発生しないという点がuseStateと異なる点です。
useRefを使った例
useRefを使った具体例を紹介します。以下のコードは、公式サイトでも例示されている「テキスト入力のフォーカス」機能です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import { useState, useRef } from "react"; const Form = () => { const [value, setValue] = useState(""); const inputRef = useRef(); return ( <div> <input type="text" ref={inputRef} value={value} onChange={(e) => setValue(e.target.value)} /> <button onClick={() => inputRef.current.focus()}> インプット要素をフォーカス </button> </div> ); }; export default Form; |
ref.currentプロパティを使用することで、参照した現在の値にアクセスすることができます。
またinputRef.current.focus()をconsole.log(inputRef)に置き換えることで「インプット要素をフォーカス」 ボタン押下時にコンソールに{current:input}というのが表示されるようになります。
参照した値を保持できることから、とてもuseStateの機能に似ていますがあくまで再レンダリングはしません。公式の以下のページにuseRefとuseStateの違いについてまとめられているので、こちらも参考になります。
The library for web and native user interfaces…
一方で公式サイトでも
Don’t read or write
ref.current
during rendering. If some information is needed during rendering, use state instead.
とあるようにレンダリング中にref.currentを使用してはいけません。レンダリング中に何をしたい場合には、useStateの方を使うようにします。
forwardRefとは何か
forwardRefは、コンポーネント内のDOMにRefオブジェクトを渡すための機能になります。つまり、子コンポーネント内の DOM に直接アクセスしたいときに使用されます。
というのもrefは、親コンポーネントから子コンポーネントへprops形式で渡して参照することができないため、 参照したい場合は、子コンポーネント内でfowardRefを使用する必要があります。
またforwardRefとuseImperativeHandleを一緒に使用することで、親コンポーネントから受け取ったrefオブジェクトをカスタマイズできるようになります。
forwardRefを使った例
forwardRefを使った具体例も紹介します。こちらのコードも公式サイトでも例示されている「テキスト入力のフォーカス」機能を例にしました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
import { useRef, forwardRef, useImperativeHandle } from "react"; const Input = forwardRef((props, ref) => { const inputRef = useRef(); useImperativeHandle(ref, () => ({ Focus() { inputRef.current.focus(); console.log("フォーカスを取得する"); }, })); return <input type="text" ref={inputRef} />; }); const Sample = () => { const ref = useRef(); return ( <> <Input ref={ref} /> <button onClick={() => ref.current.Focus()}> インプット要素をフォーカス </button> </> ); }; export default Sample; |
useImperativeHandleは、公式サイトでもあるように、第1引数に「親コンポーネントから受け取ったrefオブジェクト」、第2引数に「オブジェクトを返す関数」を設定します。
1 |
useImperativeHandle(ref, createHandle, dependencies?) |
The library for web and native user interfaces…
最後にrefは、あくまで特別に使用する場合にのみ使われるものであって(escape hatch)、頻繁に使用されるものではありません。その点を注意しつつ、Refを便利に使っていきましょう!