For this one, the example is worth a thousand words. Listing 8 (live here) shows a parent component, App
, with a child component, Expounder
. Expounder exposes a customized ref API with useImperativeHandle
, such that App
can call expound()
on the reference, causing the customized behavior (outputting “The way that can be told is not the eternal way” to the UI).
Note that the ChildComponent
in Listing 8 uses forwardRef
to include the DOM ref.
Listing 8. useImperativeHandle
const { useState, useRef, forwardRef, useImperativeHandle } = React;
const ChildComponent = forwardRef((props, ref) => {
const [count, setCount] = useState("");
const expound = () => {
setCount("The way that can be told is not the eternal way.");
};
useImperativeHandle(ref, () => ({
expound
}));
return (
<div>
<p>Count: {count}</p>
</div>
);
});
const App = () => {
const childRef = useRef(null);
const handleClick = () => {
childRef.current.expound();
};
return (
<div>
<ChildComponent ref={childRef} />
<button onClick={handleClick}>Expound</button>
</div>
);
};
So, useImperativeHandle
lets you take the first argument, the original ref, and then decorate it with whatever object is returned by the second argument function. In this case, we use a destructuring assignment to create an anonymous inline object with just an expound
method on it: useImperativeHandle(ref, () => ({ expound }));
.
The result of using the useImperativeHandle
hook is that the reference the ParentComponent
receives from ChildComponent
also has an expound
method on it, which it can call to execute the necessary functionality.
Conclusion
Using a broader palette of hooks available to React is an important aspect of leveraging the full power of the framework. You’ve seen a good sampling of some useful ones here, and React ships with even more. Beyond that, third-party hooks are available for various purposes and for integrating with frameworks. Finally, it’s possible to define your own custom hooks if the need arises.