【React】他のコンポーネントのDOMを操作できるforwardRefの使い方

React

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として渡すことができます。

React

Posted by devsakaso