forwardRefをざっくり理解
forwardRefを使う機会があったのでまとめてみました。
はじめに
まずはfowardRefについて概要を確認してみましょう。公式ページに以下の記述があります。
forwardRef lets your component expose a DOM node to parent component with a ref.
訳すと、「forwardRef は、コンポーネントが親コンポーネントに DOM ノードを参照として公開することを可能にします。」
となります。と言われてもイマイチわからないと思うので、例を交えつつfowardRefの紹介をしていきます。
forwardRefを使ってみる
早速forwardRefを使ったコンポーネントで動作確認と行きたいところですが、順を追って理解するために、まずはuseRefのみを使ったコンポーネントで動作確認していきます。
import React, { useRef } from "react";
export const MyInput = () => {
const ref = useRef();
const handleClick = () => {
ref.current.focus();
};
return (
<>
<input ref={ref} />
<button onClick={handleClick}>focus</button>
</>
);
};
import { MyInput } from "./MyInput";
import "./styles.css";
export default function App() {
return (
<div className="App">
<MyInput />
</div>
);
}
MyInput.js内で、組み込みコンポーネントinputのref属性に、useRefで生成したrefオブジェクトを渡しています。これにより、refオブジェクトのcurrentからDOMノードのAPIを使用することができます。ここでは、ボタンクリック時にfocusメソッドを使用しています。
上記の例では、refオブジェクトの生成とinputへのrefの受け渡しをMyInputコンポーネントで行なっています。では、refの生成をAppで行い、propとしてMyInputに渡すとどうなるのでしょうか。プログラムを下記の通り書き換えます。
import React from "react";
export const MyInput = ({ ref }) => {
const handleClick = () => {
ref.current.focus();
};
return (
<>
<input ref={ref} />
<button onClick={handleClick}>focus</button>
</>
);
};
import { useRef } from "react";
import { MyInput } from "./MyInput";
import "./styles.css";
export default function App() {
const ref = useRef();
return (
<div className="App">
<MyInput ref={ref} />
</div>
);
}
一見動きそうですが、コンソールを見ると下記の警告が出ています。実際にfocusボタンを押してもエラーになってしまいます。(自分も最初このように書いてコンソールに怒られました)
Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
警告を見ていきましょう。訳すと、「関数コンポーネントにrefを与えることはできません。この参照にアクセスしようとすると、失敗します。React.forwardRef()を使おうとしたのでしょうか?」となります。また、useRefのトラブルシュートを見てみましょう。その中に下記のような記述があります。
By default, your own components don’t expose refs to the DOM nodes inside them.
以上をまとめると、自作のコンポーネント内のDOMノード(今回の場合はinput)のrefを親コンポーネントに公開することはできないようです。では、どうすればいいのかというと、警告文にもありますがfowardRefを使います。
forwardRefを使用してプログラムを書き換えます。
import React, { forwardRef } from "react";
export const MyInput = forwardRef(({ ref }) => {
const handleClick = () => {
ref.current.focus();
};
return (
<>
<input ref={ref} />
<button onClick={handleClick}>focus</button>
</>
);
});
※App.jsxは変更なし
上記のようにfowardRefの引数に自作のコンポーネント渡すことで、自作のコンポーネント内のrefを公開することができました。実際にボタンを押すと最初の例と同様にinputにフォーカスが当たリます。ここで改めて、冒頭のforwardRefの概要を確認していただくと、説明に納得感があると思います。
まとめ
今回は簡単にですが、fowardRefの紹介をさせていただきました。この記事を通して、少しでも理解の助けになれば幸いです。
また、より詳しい解説・使用例は参考にある本家のサイトで確認いただければと思います。
参考
https://beta.reactjs.org/reference/react/forwardRef
https://beta.reactjs.org/reference/react/useRef