目次
Refについて
Refとはrenderメソッドで作成されたDOMノードもしくはReact要素の参照を保持するオブジェクトです。
Refオブジェクトのcurrent属性を参照することでノードにアクセスできます。
Refの使いどころ
Refを利用するユースケースは以下のとおりです。1
- フォーカス、テキストの選択およびメディアの再生の管理
- アニメーションの発火
- サードパーティのDOMライブラリとの統合
注意点として、React『Ref を使いすぎない』にも記述されているとおり、Refの多用は控えるようにしましょう。
『データフローはPropsを介して行う』『状態はStateに保存』がReactの原則です。
useRefについて
useRefとはRefオブジェクトを生成するフックです。
useRef(initialValue)
で初期値がinitialValue
のミュータブルなRefオブジェクトを生成します。
なお、ミュータブル(mutable)なデータとは『一度作成した後も値が変更できる』性質を持つデータのことをいいます。
useRefの利用手順
- useRefでRefオブジェクトを生成する
- 生成したRefオブジェクトを、参照したいDOMのref属性にセットする
- Refオブジェクトのcurrent属性を参照してノードにアクセスする
useRefの具体例
入力フォームにフォーカスする
import { FC, useRef } from "react";
const App: FC = () => {
const inputEl = useRef<HTMLInputElement>(null);
const handleClick = () => {
inputEl.current?.focus();
console.log("inputEl.current: ", inputEl.current);
// inputEl.current: <input type="text">
};
return (
<>
<input type="text" ref={inputEl} />
<button onClick={handleClick}>Focus the input</button>
</>
);
};
export default App;
DOMの高さを取得する
App.tsx
import { FC } from "react";
import { Layout } from "./Layout";
const App: FC = () => {
return (
<Layout>
<div style={{ height: "300px" }}>Example</div>
</Layout>
);
};
export default App;
Layout.tsx
import { FC, useEffect, useRef } from "react";
export const Layout: FC = ({ children }) => {
const childElement = useRef<HTMLDivElement>(null);
useEffect(() => {
const height = childElement.current?.clientHeight;
console.log("height: ", height);
// => height: 300
}, []);
return <div ref={childElement}>{children}</div>;
};
forwardRefについて
親コンポーネントから子コンポーネントのDOMにアクセスしたい、つまり親コンポーネントから子コンポーネントのRefを参照したいケースがあります。
親コンポーネントで子コンポーネントのRefを参照するには子コンポーネントにref属性を追加します。
しかし子コンポーネントが関数コンポーネントの場合、関数コンポーネントにはインスタンスがないためref属性を使用できません。1
forwardRefは関数コンポーネントでもref属性を使用できるようにするための機能です。
なお、コンポーネントをまたいでrefを自動的に渡すテクニックのことをrefのフォワーディングと呼びます。
つまり、forwardRefは関数コンポーネントでrefのフォワーディングを実現するためのものといえます。
forwardRefの利用手順
- 関数コンポーネントをforwardRef()で囲む
- 第一引数にProps、第二引数にRefを指定する
- 参照したいDOMのref属性にRefをセットする
Refを参照する場合は、useRefで生成したRefオブジェクトを当該コンポーネントのref属性に渡します。
なお、forwardRefの型定義はforwardRef<Refの型, Propsの型>
となります。
forwardRefの具体例
forwardRefの具体例として、入力フォームにフォーカスする実装を紹介します。
App.tsx
import { FC, useRef } from "react";
import { CustomInput } from "./CustomInput";
const App: FC = () => {
const inputEl = useRef<HTMLInputElement>(null);
const handleClick = () => {
inputEl.current?.focus();
console.log("inputEl.current: ", inputEl.current);
// inputEl.current: <input type="text" placeholder="this is example" />;
};
return (
<>
<CustomInput ref={inputEl} placeholder={"this is example"} />
<button onClick={handleClick}>Focus the input</button>
</>
);
};
export default App;
CustomInput.tsx
import { forwardRef } from "react";
type Props = {
placeholder: string;
};
export const CustomInput = forwardRef<HTMLInputElement, Props>(
({ placeholder }, ref) => {
return <input type="text" ref={ref} placeholder={placeholder} />;
}
);
さいごに
Twitter(@nishina555)やってます。フォローしてもらえるとうれしいです!