useImperativeHandle
は、refとして公開されるハンドルをカスタマイズできる React フックです。
useImperativeHandle(ref, createHandle, dependencies?)
リファレンス
useImperativeHandle(ref, createHandle, dependencies?)
コンポーネントのトップレベルで useImperativeHandle
を呼び出して、公開する ref ハンドルをカスタマイズします。
import { forwardRef, useImperativeHandle } from 'react';
const MyInput = forwardRef(function MyInput(props, ref) {
useImperativeHandle(ref, () => {
return {
// ... your methods ...
};
}, []);
// ...
パラメータ
-
ref
:forwardRef
のレンダー関数から2番目の引数として受け取ったref
。 -
createHandle
: 引数を取らず、公開する ref ハンドルを返す関数。その ref ハンドルは任意の型を持つことができます。通常、公開したいメソッドを持つオブジェクトを返します。 -
任意
dependencies
:createHandle
コード内で参照されるすべてのリアクティブ値のリスト。リアクティブ値には、props、state、およびコンポーネント本体内で直接宣言されたすべての変数と関数が含まれます。リンターがReact用に構成されている場合、すべてのリアクティブ値が依存関係として正しく指定されていることを確認します。依存関係のリストは、アイテム数が一定で、[dep1, dep2, dep3]
のようにインラインで記述する必要があります。Reactは、Object.is
比較を使用して、各依存関係を以前の値と比較します。再レンダリングによって一部の依存関係に変更があった場合、またはこの引数を省略した場合、createHandle
関数が再実行され、新しく作成されたハンドルがrefに割り当てられます。
戻り値
useImperativeHandle
は undefined
を返します。
使い方
親コンポーネントへのカスタムrefハンドルの公開
デフォルトでは、コンポーネントは自身のDOMノードを親コンポーネントに公開しません。例えば、MyInput
の親コンポーネントがアクセスすることを望む場合、<input>
DOMノードに対し、forwardRef
を使って明示的にオプトインする必要があります。
import { forwardRef } from 'react';
const MyInput = forwardRef(function MyInput(props, ref) {
return <input {...props} ref={ref} />;
});
上記のコードでは、MyInput
へのrefは、<input>
DOMノードを受け取ります。しかし、代わりにカスタム値を公開することもできます。公開するハンドルをカスタマイズするには、コンポーネントのトップレベルでuseImperativeHandle
を呼び出します。
import { forwardRef, useImperativeHandle } from 'react';
const MyInput = forwardRef(function MyInput(props, ref) {
useImperativeHandle(ref, () => {
return {
// ... your methods ...
};
}, []);
return <input {...props} />;
});
上記のコードでは、ref
はもはや<input>
に転送されないことに注意してください。
例えば、<input>
DOMノード全体を公開したくないが、そのメソッドのうち2つ、focus
とscrollIntoView
を公開したいとします。これを行うには、実際のブラウザDOMを別のrefに保持します。次に、useImperativeHandle
を使用して、親コンポーネントに呼び出させたいメソッドのみを持つハンドルを公開します。
import { forwardRef, useRef, useImperativeHandle } from 'react';
const MyInput = forwardRef(function MyInput(props, ref) {
const inputRef = useRef(null);
useImperativeHandle(ref, () => {
return {
focus() {
inputRef.current.focus();
},
scrollIntoView() {
inputRef.current.scrollIntoView();
},
};
}, []);
return <input {...props} ref={inputRef} />;
});
これで、親コンポーネントがMyInput
へのrefを取得した場合、そのrefに対してfocus
メソッドとscrollIntoView
メソッドを呼び出すことができるようになります。ただし、基盤となる<input>
DOMノードへの完全なアクセスは許可されません。
import { useRef } from 'react'; import MyInput from './MyInput.js'; export default function Form() { const ref = useRef(null); function handleClick() { ref.current.focus(); // This won't work because the DOM node isn't exposed: // ref.current.style.opacity = 0.5; } return ( <form> <MyInput placeholder="Enter your name" ref={ref} /> <button type="button" onClick={handleClick}> Edit </button> </form> ); }
独自の命令型メソッドの公開
命令型ハンドルを介して公開するメソッドは、DOMメソッドと完全に一致する必要はありません。例えば、このPost
コンポーネントは、命令型ハンドルを介してscrollAndFocusAddComment
メソッドを公開しています。これにより、親のPage
は、ボタンをクリックするとコメントリストをスクロールし、入力フィールドにフォーカスを当てることができます。
import { useRef } from 'react'; import Post from './Post.js'; export default function Page() { const postRef = useRef(null); function handleClick() { postRef.current.scrollAndFocusAddComment(); } return ( <> <button onClick={handleClick}> Write a comment </button> <Post ref={postRef} /> </> ); }