useImperativeHandle
useImperativeHandle
is a React Hook that lets you customize the handle exposed as a ref.
useImperativeHandle(ref, createHandle, dependencies?)
Reference
useImperativeHandle(ref, createHandle, dependencies?)
Call useImperativeHandle
at the top level of your component to customize the ref handle it exposes:
import { useImperativeHandle } from 'react';
function MyInput({ ref }) {
useImperativeHandle(ref, () => {
return {
// ... your methods ...
};
}, []);
// ...
Parameters
-
ref
: Theref
you received as a prop to theMyInput
component. -
createHandle
: A function that takes no arguments and returns the ref handle you want to expose. That ref handle can have any type. Usually, you will return an object with the methods you want to expose. -
optional
dependencies
: The list of all reactive values referenced inside of thecreateHandle
code. Reactive values include props, state, and all the variables and functions declared directly inside your component body. If your linter is configured for React, it will verify that every reactive value is correctly specified as a dependency. The list of dependencies must have a constant number of items and be written inline like[dep1, dep2, dep3]
. React will compare each dependency with its previous value using theObject.is
comparison. If a re-render resulted in a change to some dependency, or if you omitted this argument, yourcreateHandle
function will re-execute, and the newly created handle will be assigned to the ref.
Returns
useImperativeHandle
returns undefined
.
Usage
Exposing a custom ref handle to the parent component
To expose a DOM node to the parent element, pass in the ref
prop to the node.
function MyInput({ ref }) {
return <input ref={ref} />;
};
With the code above, a ref to MyInput
will receive the <input>
DOM node. However, you can expose a custom value instead. To customize the exposed handle, call useImperativeHandle
at the top level of your component:
import { useImperativeHandle } from 'react';
function MyInput({ ref }) {
useImperativeHandle(ref, () => {
return {
// ... your methods ...
};
}, []);
return <input />;
};
Note that in the code above, the ref
is no longer passed to the <input>
.
For example, suppose you don’t want to expose the entire <input>
DOM node, but you want to expose two of its methods: focus
and scrollIntoView
. To do this, keep the real browser DOM in a separate ref. Then use useImperativeHandle
to expose a handle with only the methods that you want the parent component to call:
import { useRef, useImperativeHandle } from 'react';
function MyInput({ ref }) {
const inputRef = useRef(null);
useImperativeHandle(ref, () => {
return {
focus() {
inputRef.current.focus();
},
scrollIntoView() {
inputRef.current.scrollIntoView();
},
};
}, []);
return <input ref={inputRef} />;
};
Now, if the parent component gets a ref to MyInput
, it will be able to call the focus
and scrollIntoView
methods on it. However, it will not have full access to the underlying <input>
DOM node.
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> ); }
Exposing your own imperative methods
The methods you expose via an imperative handle don’t have to match the DOM methods exactly. For example, this Post
component exposes a scrollAndFocusAddComment
method via an imperative handle. This lets the parent Page
scroll the list of comments and focus the input field when you click the button:
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} /> </> ); }