PresentationInteractive, narrated presentation of the section content.
QuizTest your understanding of the section content.
ContentDetailed description of the section content.
Understanding and Using the useImperativeHandleHook in React
Have you ever needed to customise the way your child component interacts with its parent? Imagine you’re building a reusable component like a modal or an input field, and you want the parent component to have control over specific actions—like focusing on an input or opening the modal.
In React, child components expose their refs to the parent using the ref attribute. However, sometimes the default behaviour of refs doesn’t suit your needs. This is where useImperativeHandle comes to the rescue. It allows you to define what a parent component can "see" and "control" when interacting with a child component.
By the end of this lecture, you'll understand:
- What
useImperativeHandledoes. - How to use it effectively in real-world scenarios.
- When (and when not) to use it.
1. Understanding Refs and the Default Behavior
Refs in React are a way to directly access a DOM element or a child component instance. By default:
- The
refattribute gives access to the DOM node (e.g.,<input>) or the component instance. - However, there’s no way to customise what gets exposed to the parent.
For example:
function ChildComponent() {
return <input type="text" />;
}
function ParentComponent() {
const inputRef = React.useRef();
React.useEffect(() => {
inputRef.current.focus(); // Directly focuses the input
}, []);
return <ChildComponent ref={inputRef} />;
}
This works fine for accessing basic DOM elements. But what if you want to expose custom methods or only specific properties to the parent? Let’s look at how useImperativeHandle fits in.
2. What is useImperativeHandle?
useImperativeHandle allows you to control the value exposed through a ref from a child component. It enables you to:
- Hide certain implementation details.
- Expose custom methods or state to the parent.
Syntax
useImperativeHandle(ref, createHandle, [dependencies])
ref: The forwardedreffrom the parent component.createHandle: A function that returns the object to expose.[dependencies]: Optional. React will recreate the handle when these values change.
3. 👾Basic Example
Let’s create a simple component where the parent can focus on an input via a custom method.
Step 1: Forward the Ref
To use useImperativeHandle, you must forward the ref to the child component using React.forwardRef.
const InputWithFocus = React.forwardRef((props, ref) => {
const inputRef = React.useRef();
// Step 2: Use useImperativeHandle to expose methods
React.useImperativeHandle(ref, () => ({
focus: () => inputRef.current.focus(),
}));
return <input ref={inputRef} type="text" />;
});
Step 3: Access the Custom Method from the Parent
Now, the parent can call the focus method.
function ParentComponent() {
const inputRef = React.useRef();
return (
<div>
<InputWithFocus ref={inputRef} />
<button onClick={() => inputRef.current.focus()}>
Focus Input
</button>
</div>
);
}
Here, the parent only has access to the focus method, not the entire DOM node.
4. Real-World Use Case: A Modal Component
Imagine a reusable modal where the parent can control when to open, close, or reset its content.
const Modal = React.forwardRef((props, ref) => {
const [isOpen, setIsOpen] = React.useState(false);
React.useImperativeHandle(ref, () => ({
open: () => setIsOpen(true),
close: () => setIsOpen(false),
toggle: () => setIsOpen((prev) => !prev),
}));
return isOpen ? (
<div style={{ border: "1px solid black", padding: "1rem" }}>
<h2>Modal</h2>
<button onClick={() => setIsOpen(false)}>Close</button>
</div>
) : null;
});
In the parent:
function ParentComponent() {
const modalRef = React.useRef();
return (
<div>
<button onClick={() => modalRef.current.open()}>Open Modal</button>
<Modal ref={modalRef} />
</div>
);
}
5. When to Use and When Not to Use
Use When:
- You need to customize the exposed behavior of a child component.
- You’re creating reusable components with specific methods like modals, tooltips, or inputs.
Avoid When:
- The parent doesn’t need to control the child directly.
- You can achieve the behavior through props or callbacks.
6. Advantages and Disadvantages
👍🏽 Advantages:
- Encapsulation: Control what the parent can access.
- Flexibility: Expose only relevant details or methods.
👎🏽 Disadvantages:
- Complexity: Can make components harder to understand.
- Overhead: Adds extra code; use it only when necessary.
Conclusion
Key Takeaways:
useImperativeHandlecustomizes what a child component exposes via aref.- It’s especially useful for reusable components like modals and inputs.
- Use it sparingly—prefer simpler patterns when possible.
Common Pitfalls:
- Forgetting to use
React.forwardRef. - Exposing too many details, breaking encapsulation.
By mastering useImperativeHandle, you can build more flexible and maintainable React components while maintaining control over their behavior.
Assessment
1. Coding Exercise
Create a Dropdown component where the parent can:
- Open the dropdown.
- Close the dropdown.
- Check if the dropdown is open.
Starter code:
const Dropdown = React.forwardRef((props, ref) => {
const [isOpen, setIsOpen] = React.useState(false);
React.useImperativeHandle(ref, () => ({
// Implement methods here
}));
return isOpen ? (
<div style={{ border: "1px solid black" }}>
<p>Dropdown Content</p>
<button onClick={() => setIsOpen(false)}>Close</button>
</div>
) : null;
});
function ParentComponent() {
const dropdownRef = React.useRef();
return (
<div>
<button onClick={() => dropdownRef.current.open()}>Open Dropdown</button>
<Dropdown ref={dropdownRef} />
</div>
);
}
2. Quiz
No hints available.
