ReactJS - useImperativeHandle Hook



The useImperativeHandle is a React Hook introduced in React 18. This hook lets us customize the handle that is exposed as a ref for a child component. This is very useful when we need to connect with a child component immediately, which means we want to immediately access and call methods or attributes on the child component.

Syntax

useImperativeHandle(ref, createHandle, optional_dependency)

Parameters

  • ref − This is a special tool that helps us connect with a child component. It is received as the second argument when we are creating a child component with the help of forwardRef.

  • createHandle − It is a set of instructions for what we want to be able to do with the child component. This is what we return from useImperativeHandle.

  • optional _dependencies − We need to list all the things (like props, state, and variables) that we are using inside the createHandle part. So React will check these things and make sure they don't change unexpectedly. If they do, it will update our special tool.

Return Value

This method returns undefined.

How to use it?

We can use ‘useImperativeHandle’ at the top level of the component to customise the ref handle it exposes −

import { forwardRef, useImperativeHandle } from 'react';

const MyComp = forwardRef(function MyComp(props, ref) {
   useImperativeHandle(ref, () => {
      return {
         // the methods we want in our code ...
      };
   }, []);

Examples

So we can use this hook in two different ways. First by creating a custom ref handle available to the parent component and secondly by exposing our own imperative approaches. And we will discuss these two methods one by one further.

Making a custom ref handle available to the parent component

React components do not provide direct access to the underlying DOM elements by default. We will have to use forwardRef to allow a parent component to access the ;input> DOM node in a child component.

import { forwardRef } from 'react';

const InputComp = forwardRef(function InputComp(props, ref) {
   return <input {...props} ref={ref} />;
});

This code will return the actual <input> DOM node to a ref given to InputComp.

Sometimes we do not want to expose the complete DOM node, but just a part of its methods or attributes. For example, focusing and scrolling a child component without exposing the whole DOM node. We can customize the exposed handle with the help of useImperativeHandle hook.

For Example

import { forwardRef, useImperativeHandle } from 'react';

const InputComp = forwardRef(function InputComp(props, ref) {
   useImperativeHandle(ref, () => ({
   focus() {
      inputRef.current.focus();
   },
   scrollIntoView() {
      inputRef.current.scrollIntoView();
   },
   }), []);
   
   return <input {...props} />;
});

In the above example, we are modifying the parent component's exposed handle. InputComp's focus and scrollIntoView methods can be called by the parent component. But it will not have direct access to the DOM node <input>.

Example − Short Application to understand this Hook

import React, { forwardRef, useImperativeHandle, useRef, useState } from 'react';

const Counter = forwardRef(function Counter(props, ref) {
   const [count, setCount] = useState(0);   
   const increment = () => {
      setCount(count + 1);
   };   
   const reset = () => {
      setCount(0);
   };   
   useImperativeHandle(ref, () => ({
      increment,
      reset,
   }), []);   
   return (
      <div>
         <p>Counter: {count}</p>
      </div>
   );
});

function App() {
   const counterRef = useRef();   
   const handleIncrement = () => {
      counterRef.current.increment();
   };
   
   const handleReset = () => {
      counterRef.current.reset();
   };
   
   return (
      <div>
         <Counter ref={counterRef} />
         <button onClick={handleIncrement}>Increment Count</button>
         <button onClick={handleReset}>Reset</button>
      </div>
   );
}
export default App;

Output

counter

Example − Exposing our own imperative approaches

In a component, we can create our own custom methods and give them to its parent. These custom methods do not have to be the same as built-in methods of HTML elements.

Imagine we have an InputForm component that displays a simple input field component (InputForm) that can be scrolled into view and focused when a button is pressed. When we click a button in the parent component named App, this method on the input field is executed, causing it to scroll into view and receive focus.

import React, { forwardRef, useRef, useImperativeHandle } from 'react';

const InputForm = forwardRef((props, ref) => {
   const inputRef = useRef(null);
   
   useImperativeHandle(ref, () => ({
      scrollAndFocus() {
         inputRef.current.scrollIntoView();
         inputRef.current.focus();
      }
   }), []);
   
   return <input type="text" ref={inputRef} placeholder="Type here..." />;
});

function App() {
   const inputRef = useRef();
   
   const handleButtonClick = () => {
      inputRef.current.scrollAndFocus();
   };
   
   return (
      <div>
         <button onClick={handleButtonClick}>Scroll and Focus</button>
         <InputForm ref={inputRef} />
      </div>
   );
}

export default App;

In the above example we have demonstrated how to use forwardRef and useImperativeHandle to scroll and focus on an input field.

Summary

In version 18, useImperativeHandle is a helpful React Hook that allows immediate interaction with child components by changing the ref. It is useful when we need quick access to a child component's functions or attributes. By using this hook, we can create a connection and define what actions we want to perform on the child component, giving smooth communication and updates when needed, with the method returning undefined.

reactjs_reference_api.htm
Advertisements