【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