← Back toMaster of React ref

Expose methods of a component using useImperativeHandle()

Written byPhuoc Nguyen
Created
25 Oct, 2023
Tags
carousel slider, React.forwardRef(), React.useImperativeHandle()
Sometimes, we may want to give the parent component more control over the child component by allowing access to specific methods or properties. The `useImperativeHandle()` hook, used in combination with `forwardRef()`, can help us achieve this.
With `useImperativeHandle()`, we can define a set of functions and values that will be accessible on the ref object from outside of the component. This is especially useful when we need to call a method on a child component from its parent, such as when triggering an animation or fetching new data.
Let's say we have a `Slider` component, and we want to expose some methods that allow users to navigate to the previous or next item, or jump to any item. We can use `useImperativeHandle()` to make this happen.

Introducing the Slider component

Let's keep things simple and work with the `Slider` component we created earlier. Just to refresh your memory, here's how it works:
In this example, the `Slider` component includes arrows on the sides for users to navigate to the previous and next items. There are also dots at the bottom to allow users to jump to any item they want.
To better understand the power of `useImperativeHandle`, we've removed the animation of the current dot item, leaving the `Slider` component with basic functionalities. However, it still includes everything for navigation. What if we exposed a few navigation methods, so users have full control of the navigation UI but still have the full advantage of the slider, such as smooth animation when navigating between items?
For example, imagine a custom slider component with several methods for controlling navigation. These methods need to be accessible to the parent component so that it can control the slider navigation.
Let's dive into the next section to get a better understanding of the basics behind `useImperativeHandle()`.

Understanding the syntax of useImperativeHandle

The `useImperativeHandle()` hook is a powerful tool that takes two arguments. The first argument is the `ref` object we want to assign our functions and values to, while the second argument is a function that returns an object containing those functions and values.
Here's an example of how we can use `useImperativeHandle()` to expose methods of the `Slider` component:
tsx
interface SliderMethods {
goToPreviousItem: () => void;
goToNextItem: () => void;
jump: (index: number) => void;
};

const Slider = React.forwardRef<SliderMethods>((props, ref) => {
const goToPreviousItem = () => {
...
};

const goToNextItem = () => {
...
};

const jump = (index) => {
...
};

React.useImperativeHandle(ref, () => ({
goToPreviousItem,
goToNextItem,
jump,
}));

return (
// Render slider UI ...
);
});
In this example, we create an interface called `SliderMethods` that lists all the necessary methods for slider navigation. These methods include `goToPreviousItem()`, `goToNextItem()`, and `jumpToItem()`. We then pass this interface as the first argument to `React.forwardRef`.
To make these methods accessible to the parent component, we use `useImperativeHandle`. This function takes a second argument, which is a function that returns an object with all the necessary methods.
Now, these methods can be accessed on the ref object in the parent component. It's like giving the parent component a key to unlock the methods it needs to control the slider.

Using the Slider component's exposed methods

How can we use the navigation methods that are provided by the `Slider` component? Well, it's actually quite simple, just like using a regular ref.
To start, we need to create a reference to the Slider component using `useRef()`, and then attach it to the `ref` attribute of the corresponding element. Here's how to do it:
tsx
const sliderRef = React.useRef();

<Slider ref={sliderRef}>
...
</Slider>
Calling the Slider component methods is a breeze – simply access it through the `current` property of the ref.
tsx
const handleClickNextButton = () => {
const slider = sliderRef.current;
if (slider) {
slider.goToNextItem();
}
};

<div className="container__next" onClick={handleClickNextButton}></div>
When the user clicks the Next button in this example, it triggers the `handleClickNextButton` function. This function retrieves the reference to the `Slider` component from `sliderRef.current`. If the reference exists, it calls the `goToNextItem()` method, which navigates to the next item in the slider.
Check out the final demo below! You can navigate between slider items by clicking either the arrows or the dots.

Conclusion

By using `useImperativeHandle`, we can create a well-defined and clean API for our component. This API allows users to control specific functionalities while still maintaining internal state and functionality. This way, we can ensure that the parent component doesn't accidentally modify any internal state or call any unnecessary functions.
In summary, `useImperativeHandle` gives us control over which methods or values we want to expose to the parent component. This makes our components more composable and easier to use in different contexts. It's a powerful tool that should be used with caution, but it can greatly improve the user experience of our applications.
If you found this post helpful, please consider giving the repository a star on GitHub or sharing the post on your favorite social networks 😍. Your support would mean a lot to me!

Questions? 🙋

Do you have any questions about front-end development? If so, feel free to create a new issue on GitHub using the button below. I'm happy to help with any topic you'd like to learn more about, even beyond what's covered in this post.
While I have a long list of upcoming topics, I'm always eager to prioritize your questions and ideas for future content. Let's learn and grow together! Sharing knowledge is the best way to elevate ourselves 🥷.
Ask me questions

Recent posts ⚡

Newsletter 🔔

If you're into front-end technologies and you want to see more of the content I'm creating, then you might want to consider subscribing to my newsletter.
By subscribing, you'll be the first to know about new articles, products, and exclusive promotions.
Don't worry, I won't spam you. And if you ever change your mind, you can unsubscribe at any time.
Phước Nguyễn