React useImperativeHandle Unleashed

Pro Members Only

This lesson is available if you have an active subscription.

Alternatively, some member might be able to gift it to you.

If you already have a subscription, you can sign in.

React useImperativeHandle Unleashed

Subscription Required

You must have an active subscription to access this content.
If you already have a subscription, you can sign in.

Creating Custom Component APIs

React components can provide a custom api to their parent components by utilizing the useImperativeHandle hook.

This is demonstrated in the below example with our CustomComponent.

CustomComponent.tsx
App.tsx
import { useImperativeHandle } from 'react';
import { forwardRef } from 'react';

export type Handle = {
logMessage: (value: string) => void,
logError: (value: string) => void,
};

export const CustomComponent = forwardRef(
function CustomComponent(props: {}, ref: React.Ref<Handle>) {
useImperativeHandle(ref, () => ({
logMessage: (value: string) => {
console.log(value);
},
logError: (value: string) => {
console.error(value);
},
}));
return (
<div>Custom Component</div>
);
}
);

useImperativeHandle cheatsheet

Here's a handy reference:

  • Create a type for the API the component will provide called Handle
  • Accept a ref as React.Ref<Handle>
  • Associate the ref with the handle using useImperativeHandle(ref, () => Handle)

Email Form Example

An example that shows the beauty of the useImperativeHandle hook is an email component that allows its consumers to focus the subject or the body.

App.tsx
EmailForm.tsx
import { useRef, useState } from 'react';
import { EmailForm, EmailFormHandle } from './EmailForm';

export default function App() {
const [subject, setSubject] = useState('');
const [body, setBody] = useState('');

const emailFormRef = useRef<EmailFormHandle>(null);

return (
<>
<EmailForm
subject={subject}
setSubject={setSubject}
body={body}
setBody={setBody}
ref={emailFormRef}
/>

<button onClick={() => emailFormRef.current?.focusSubject()}>Focus Subject</button>
<button onClick={() => emailFormRef.current?.focusBody()}>Focus Body</button>
</>
);
}
javascript
typescript
react
playwright

Enjoy free content straight from your inbox 💌

No spam, unsubscribe at any time.

Transcript

00:00

Founding Revs by themselves is pretty great for thin wrappers on native components. But if you want to take it to the next level and provide a neat API for consumers of your custom components, then that's exactly when the use imperative handle hook comes into play. So let's take a look. The use imperative handle hook works on top of revs within custom components. So first we need to create a custom component that utilizes forward drift. We bring in the forward drift from React and then we define our custom component, use forward drift, and then within our component accept the props

00:33

and a ref which we currently have defined as an empty object. Now in addition to using native elements as the ref type, we can actually define our own custom handle to use with the ref. Here we have defined a type for our ref, which will have a log message function and a log error function. Now to specify that this is the type that we want our ref to return, we passed this handle type in to react or ref for a generic argument. Now that we have the type for the ref completely defined, we can bring in the use imperative handle hook,

01:05

which comes from React just like the other hooks that we've seen like you state. This hook allows us to associate the past in ref with an API that conforms to that handle data type. The use imperative handle hook takes two arguments. The first is a ref and the second is a callback function, which should return the API that we want to associate with that ref. Now before we see it in action, let's do a quick recap. We define the type of the handle, we say that our ref is going to be off that handle type, and then we utilize used imperative handle

01:37

to associate the ref. With that API, let's use this custom component and the API that it provides within our application. The first step of course will be to bring in the type for the handle and the custom component from the custom component module. With React built in Use ref, we specify that we intend to get back an API of type handle for our custom component rif. When we render out our custom component for the ref prop, we pass in this custom component RIF that we've created using Use Ref. And now when this component gets rendered,

02:10

custom component ref dot current will point to an API that conforms to that handle data type. So let's just create two simple buttons to invoke the different functions that that handle provides. One is that log message function and the other is log error. When we run this application in the browser and click the buttons for log message or the log error, the API that we provided from a custom component gets invoked and we can see the logs on the console. Now that we know how the use imperative handle hook can be used to define your own custom rev

02:41

APIs, the sky is really the limit. So let's take a look at a bit more real world example. For this example, we will create a very simple email form and this form will have two simple fields which will be subject and body. And for this purpose we have some simple props, which is subject set, subject body, Set body. Now this form component will provide a nice convenient way for the consumers to focus on the individual fields. And for that purpose we define the email form handle which provides functions for focusing on the subject or the body. Now, with these simple type definitions

03:13

and our objectives out of the way, let's define our email form component. Now, because we intend to provide the convenient API, we are going to use the forward ref function. And then within the component definition we take in the props and we take in the ref for an email form handle. Within the function body, we define refs for the subject and the body, and then within use imperative handle within the functions focus, subject and focus body, we use these subject and body riffs to focus on the individual fields. With this simple logic out of the way, the only thing

03:46

that's remaining is for us to render out some simple HTML. We will render a label and an input for the subject and a label and a text area for the body. And the key thing to note over here is that we are passing in the ref props so that we can eventually use the subject ref and the body ref within our imperative handle with the email form component completed, let's try to use it within our application. We bring in the email form, we bring in the email form props, and then we bring in the email form handle. From the email form module, we define two simple state variables, one

04:18

for the subject and one for the body. And then we define the ref for the email form, specifying that it will be of the type email form handle. When we render out the email form, we are sure to pass in all of the props that it needs, which is subject body and the ref. And then to allow the user to focus on the individual fields, we create two simple buttons. And then within the on clicks, we invoke the API that we have attached to the ref, which is focus subject and focus body. You can see how nice this API looks because we've given it specific names. Now let's jump into the UI and test it out.

04:52

We provide a subject value, for example, high, and then within the body we write something like, how are you? And then we can click the individual buttons to focus on the individual fields. One final consideration that I have for you is that if you can use something as a prop, you should not use a ref, for example, instead of exposing an imperative handle, like open and close from a model component, it is better to use and is open prop. And then based on that, decide if the model should be open or not. But if you're looking at providing a richer API,

05:24

then forward ref combined with use, imperative handle is an excellent choice. As always, thank you for joining me and I'll see you in the next one.