4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

useImperativeHandleの使い方

Last updated at Posted at 2024-06-24

今日は、useImperativeHandleを使いつつ学んでいきます。
公式:useImperativeHandle

前提

forwardRefについて知っておく必要がりますので、まずはこちらを読んでおいてくださいね!
公式:forwardRef

  • ざっくりいうと...。親は子にrefを渡す、子はforwardRefしておくことで、子の要素を親で触れるようにできるよというものデス。

useImperativeHandleって何?

親コンポーネントが子コンポーネントの内部メソッドを呼び出せるようにするフックです。!
これにより、コンポーネントの内部実装を隠しつつ、親に特定の機能だけを公開できます。
親は必要な操作だけを行え、子の詳細が変更されても影響を受けません!

基本の使い方

import React, { useRef, useImperativeHandle, forwardRef } from 'react';

// 子コンポーネント
const CustomInput = forwardRef((props, ref) => {
  const inputRef = useRef(null);

  useImperativeHandle(ref, () => ({
    setFocus: () => {
      inputRef.current.focus();
    }
  }));

  return <input ref={inputRef} {...props} />;
});

// 親コンポーネント
const Form = () => {
  const inputRef = useRef(null);

  const handleClick = () => {
    inputRef.current.setFocus();
  };

  return (
    <div>
      <CustomInput ref={inputRef} />
      <button onClick={handleClick}>inputにフォーカスする</button>
    </div>
  );
}

親コンポーネントからrefを渡す

<CustomInput ref={inputRef} />

親側で定義した const inputRef = useRef(null); を、CustomInputに渡します。

子コンポーネントでuseImperativeHandleを使用

useImperativeHandle(ref, () => ({
  setFocus: () => {
    inputRef.current.focus();
  }
}));

ここでrefは親から渡されたものであり、そのrefに対してsetFocusメソッドを定義しています。
このsetFocusメソッドは、親から呼び出すことができます。

もうちょっとメソッドを増やしてみます

import React, { useRef, useImperativeHandle, forwardRef } from 'react';

// 子コンポーネント
const CustomInput = forwardRef((props, ref) => {
  const inputRef = useRef(null);

  useImperativeHandle(ref, () => ({
    setFocus: () => {
      inputRef.current.focus();
    },
    clearInput: () => {
      inputRef.current.value = '';
    },
    highlightText: () => {
      inputRef.current.select();
    }
  }));

  return <input ref={inputRef} {...props} />;
});

// 親コンポーネント
const Form = () => {
  const inputRef = useRef(null);

  const handleFocus = () => {
    inputRef.current.setFocus();
  };

  const handleClear = () => {
    inputRef.current.clearInput();
  };

  const handleSelectText = () => {
    inputRef.current.highlightText();
  };

  return (
    <div>
      <CustomInput ref={inputRef} />
      <button onClick={handleFocus}>フォーカス</button>
      <button onClick={handleClear}>クリア</button>
      <button onClick={handleSelectText}>テキスト選択</button>
    </div>
  );
}

子がuseImperativeHandleして公開したメソッドを、refを通じて親が利用していることがわかりますね!

依存配列

useImperativeHandleuseEffectのように依存配列を持てます。

  const [value, setValue] = useState('');
 
  useImperativeHandle(ref, () => ({
    setFocus: () => {
      inputRef.current.focus();
    },
    clearInput: () => {
      inputRef.current.value = '';
      setValue('');
    },
    highlightText: () => {
      inputRef.current.select();
    }
  }), [value]); // 依存配列として`value`を指定

useImperativeHandleに依存配列を入れたとき

  • 依存関係が変化したときのみハンドルを再生成し、パフォーマンスを最適化

useImperativeHandleに依存配列を入れなかったとき

  • コンポーネントが再レンダリングされる度にuseImperativeHandleの関数が再実行され、公開されるインペラティブハンドルが毎回再生成されます。
    • インペラティブハンドル? : 親が子の内部メソッドやプロパティにアクセスできる仕組み。
  • パフォーマンスに悪影響を与える可能性があります!

useImperativeHandleを使わなくてもよい

import React, { useRef } from 'react';

function useCustomInput() {
  const inputRef = useRef(null);

  const setFocus = () => {
    inputRef.current.focus();
  };

  const clearInput = () => {
    inputRef.current.value = '';
  };

  return {
    inputRef,
    setFocus,
    clearInput,
  };
}

// 子コンポーネント
const CustomInput = ({ inputRef, ...props }) => (
  <input ref={inputRef} {...props} />
);

// 親コンポーネント
const Form = () => {
  const { inputRef, setFocus, clearInput } = useCustomInput();

  return (
    <div>
      <CustomInput inputRef={inputRef} />
      <button onClick={setFocus}>フォーカス</button>
      <button onClick={clearInput}>クリア</button>
    </div>
  );
}

まとめ

今日はuseImperativeHandleの使い方について学びました!
このフックを使うことで、親が子の内部メソッドを呼び出せるようになり、再利用性や柔軟性が向上しますね!
場合によっては、useImperativeHandleを使わなくても、カスタムフックやヘルパー関数を使って同様の機能を実現できます。

これらの方法を使い分けて、Reactコンポーネントの設計をより柔軟かつ効率的に行いましょう。

4
0
0

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
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?