15
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

refとforwardRef 、 useImperativeHandleについて調べた時のノート

Last updated at Posted at 2022-05-27

この記事の内容

Reactは基本操作しか知らない人が、forwardRefuseImperativeHandleが出てくるコードを修正した時にわからないことを調べた記事です。

主な参考文献

公式ドキュメント。本記事のコードはここにあったものを引用し、状況に応じて多少アレンジしています。

この記事も丁寧で助かった

refオブジェクト

コンポーネントがマウントされたときからアンマウントされるときまで存在し続ける、書き換え可能なオブジェクトのこと。useRef()を使って作成。(ついでに、renderとマウント・アンマウントの違いが曖昧だったので調べました。)

↓こんなふうに作るよ

const refContainer = useRef(initialValue);

↓こんなふうに使うよ

function TextInputWithFocusButton() {
  const inputEl = useRef(null); // 1. refオブジェクトを作成
  const onButtonClick = () => {  //3. inputEl.currentで下記のinput要素にアクセスできる
    // `current` points to the mounted text input element
    inputEl.current.focus();
  };
  return (
    <>
      <input ref={inputEl} type="text" />  {/* 2. ref属性でinputElを指定すると */}
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}

<input ref={inputEl} /> のように、React(ここでは<input />)に refオブジェクトを渡した場合、ReactはDOMノードに変更があるたびに .current プロパティをその DOM ノードに設定する。

useRefは値を中に保持しておくことができる。
-> 関数コンポーネントを再レンダーした際に、前回のレンダー時のデータを取得することが可能

forwardRef

React.forwardRefはrefオブジェクトを配下のツリーの別のコンポーネントに受け渡す React コンポーネントを作成します。

↓こんなふうに使うよ

const FancyButton = React.forwardRef((props, ref) => ( // 2. FancyButtonが第二引数のrefに入っている
  <button ref={ref} className="FancyButton">
    {props.children} //3. "Click me!"の文字の入った buttonができる
  </button>
));

const App = () => {
  const ref = React.createRef();
  return(
    <FancyButton ref={ref}>Click me!</FancyButton>; // 1. FancyButtonコンポーネントを呼び出すと
  )
};

この機能を利用すると、親コンポーネント(ここではApp)側から子コンポーネント内の要素を操作することができる。

useImperativeHandle

useImperativeHandle は ref が使われた時に親コンポーネントに渡されるインスタンス値をカスタマイズするのに使います。

↓こんなふうに使うよ

const FancyInput = (props, ref) => {
  const inputRef = useRef();
  useImperativeHandle(ref, () => ({
    focus: () => { // `focus()`メソッドを作っている
      inputRef.current.focus();
    }
  }));
  return <input ref={inputRef} type="text" ... />;
}

const WrapperFancyInput = React.forwardRef(FancyInput);

const App = () => {
  const inputRef = useRef();
  const onClick = () => {
    inputRef.current.focus();  // FancyInput内のinputにフォーカス
  };

  return (
    <div>
      <WrapperFancyInput ref={inputRef} />
      <button type="button" onClick={onClick}>
        click
      </button>
    </div>
  );
}

この例では、<WrapperFancyInput ref={inputRef} /> をレンダーする親コンポーネント(ここではApp)は inputRef.current.focus() (←FancyInput内に記したメソッド)を呼べるようになります。

感想

複雑なコンポーネントの実装中。ここで調べたことが役に立つと良いなーと思いつつ、簡単に終わります。

15
6
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?