【React】他のコンポーネントのDOMを操作できるforwardRefの使い方
Reactで他のコンポーネントのDOMを操作できるforwardRefの使い方を紹介します。
Reactで他のコンポーネントのDOMを操作できるforwardRefの使い方
コンポーネントをまたいでDOM操作したいことケースがたまにでてきます。
そのようなときに使うのが、forwardRefです。
たとえば、ref属性にuseRefの変数をpropsとして渡そうとすると以下のようなエラーメッセージがでます。
Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
といったエラーメッセージや、
Warning: Input: `ref` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop.
というエラーメッセージが出たときforwardRefを使う場面です。
具体的には以下のようなケースです。
ダメな例
Sample.jsでInputコンポーネントを読み込み、Sample.jsにあるボタンをクリックするとInputコンポーネントのinputにフォーカスを当てたいとします。
Sample.js
import { useRef } from "react";
import Input from "./Input";
const Sample = () => {
const ref = useRef();
return (
<>
<Input ref={ref} />
<button onClick={() => ref.current.focus()}>
インプット要素をフォーカスする
</button>
</>
);
};
export default Sample;
Input.js
const Input = ({ref}) => {
return <input type="text" ref={ref} />;
};
export default Input;
上のようにすると、上記で説明したエラーメッセージがコンソールに表示されます。
forwardRefを正しく使っている例
Sample.js
import { useRef } from "react";
import Input from "./Input";
const Sample = () => {
const ref = useRef();
return (
<>
<Input ref={ref} />
<button onClick={() => ref.current.focus()}>
インプット要素をフォーカスする
</button>
</>
);
};
export default Sample;
Input.js
import { forwardRef } from "react";
const Input = forwardRef((props, ref) => {
return <input type="text" ref={ref} />;
});
export default Input;
ちょっと変わったカタチになりますが、forwardRef()の中に関数をまるっと入れ込みます。
第一引数には、propsをとり、第二引数にrefをとります。
こうすることで、コンポーネントをまたいでrefの受け渡しが可能になります。
forwardRefを使わずにref属性を渡す方法
ref属性は特別な意味があるため、refというワードを使わず、他の名称にすることでエラーを回避できます。
たとえば以下のようにします。
Sample.js
import { useRef } from "react";
import Input from "./Input";
const Sample = () => {
const ref = useRef();
return (
<>
<Input inputRef={ref} />
<button onClick={() => ref.current.focus()}>
インプット要素をフォーカスする
</button>
</>
);
};
export default Sample;
Input.js
const Input = ({inputRef}) => {
return <input type="text" ref={inputRef} />;
};
export default Input;
このように、ref以外の名称の変数にすれば普通にpropsとして渡すことができます。