How to Use useImperativeHandle Hook in React
The useImperativeHandle Hook in React allows you to
customize the instance value that is exposed to parent components when
using a ref. This article provides a clear, step-by-step guide on how to
implement, use, and update the values returned by
useImperativeHandle by pairing it with
forwardRef to control child components from a parent
component.
Understanding the Basics
By default, React components do not expose their internal DOM nodes
or state to parent components. To change this, you must wrap the child
component in forwardRef and use
useImperativeHandle to define the specific methods or
properties the parent component can access.
Step-by-Step Implementation
1. Create the Child Component with forwardRef
To use useImperativeHandle, your child component must
accept a ref parameter. You achieve this by wrapping the
component in forwardRef.
import { useState, useImperativeHandle, forwardRef } from 'react';
const CustomInput = forwardRef((props, ref) => {
const [value, setValue] = useState('');
// Expose custom methods to the parent
useImperativeHandle(ref, () => ({
focus: () => {
document.getElementById('custom-input').focus();
},
clear: () => {
setValue('');
},
getValue: () => value
}), [value]); // Dependency array ensures the parent gets the updated value
return (
<input
id="custom-input"
type="text"
value={value}
onChange={(e) => setValue(e.target.value)}
/>
);
});
export default CustomInput;2. How to Update useImperativeHandle Values
To ensure the parent component always receives updated state values
from the child, you must pass a dependency array as the third argument
to useImperativeHandle, just like you would with
useEffect or useMemo.
In the example above, [value] is passed as a dependency.
If you omit this dependency array, the helper functions inside the hook
will capture the initial state (closure) and will not reflect subsequent
state updates when called by the parent.
3. Consume the Ref in the Parent Component
Once the child component is configured, the parent component can
declare a ref using useRef, attach it to the child, and
call the exposed methods.
import { useRef } from 'react';
import CustomInput from './CustomInput';
function ParentComponent() {
const inputRef = useRef(null);
const handleFocus = () => {
inputRef.current.focus();
};
const handleClear = () => {
inputRef.current.clear();
};
const handleLogValue = () => {
alert(inputRef.current.getValue());
};
return (
<div>
<CustomInput ref={inputRef} />
<button onClick={handleFocus}>Focus Input</button>
<button onClick={handleClear}>Clear Input</button>
<button onClick={handleLogValue}>Show Value</button>
</div>
);
}Key Considerations
- Use Sparingly: Imperative code using refs should be
avoided for most common tasks. Try to use declarative props and state
lifting before opting for
useImperativeHandle. - Dependency Array: Always include any state or props
used inside the
useImperativeHandlecallback in its dependency array to prevent stale closures.