React useRef Use Cases and Examples
Published: 2024-01-26 17:24:45

An explanation of why and how to use React.js useRef Hook

In React.js, useRef is a hook that allows you to create a mutable reference to an element or a value. Unlike the useState hook, updating a useRef does not trigger a re-render of the component. It's commonly used for accessing and managing DOM elements directly, storing persistent values, or working with values that should not trigger a re-render.

The basic syntax of useRef is as follows:

> const refContainer = useRef(initialValue);

**Primary Uses of useRef**
1. Accessing DOM elements
One of the most common use cases of useRef is accessing DOM elements. Instead of using document.getElementById or other DOM queries, you can use useRef to directly reference an element within your component.

### 

> import React, { useRef } from 'react';
> const ExampleComponent = () => {
>   const inputRef = useRef(null);
>   const handleClick = () => {
>     // Focus the input element on button click
>     inputRef.current.focus();
>   };
>   return (
>     <div>
>       <input ref={inputRef} type="text" />
>       <button onClick={handleClick}>Focus Input</button>
>     </div>
>   );
> };

2. Storing previous values
You can use useRef to store a value that persists across renders but doesn't trigger a re-render when updated. This can be useful when you need to keep track of previous values without triggering unnecessary renders.

> import React, { useEffect, useRef } from 'react';
> const PreviousValueComponent = ({ value }) => {
>   const prevValueRef = useRef();
>   useEffect(() => {
>     prevValueRef.current = value;
>   }, [value]);
>   return (
>     <div>
>       <p>Current Value: {value}</p>
>       <p>Previous Value: {prevValueRef.current}</p>
>     </div>
>   );
> };

3. Working with external libraries
Sometimes, when integrating external libraries that expect a mutable reference to some data, useRef can be handy.

> import React, { useEffect, useRef } from 'react';
> import externalLibrary from 'some-external-library';
> const ExternalLibraryComponent = () => {
>   const dataRef = useRef([]);
>   useEffect(() => {
>     // Update the external library with the latest data
>     externalLibrary.updateData(dataRef.current);
>   }, []);
>   // ... rest of the component
> };

Remember that since useRef doesn't trigger re-renders, if you need to update the component and reflect the changes in the UI, you should use useState instead. Use useRef only when you need to manage a mutable value or reference that should not affect the component's rendering.

**useImperativeHandle**
useImperativeHandle is a React hook that allows you to customize the instance value that is exposed to parent components when using ref on a child component. It's often used in combination with forwardRef and useRef to provide a more controlled and explicit way of interacting with a child component's methods or properties from its parent.

Let’s create an example using useRef, useImperativeHandle, and forwardRef to build a simple custom input component that exposes a method to focus the input programmatically:

> // Child Component (CustomInput.js)
> import React, { useRef, useImperativeHandle, forwardRef } from 'react';
> const CustomInput = forwardRef((props, ref) => {
>   const inputRef = useRef(null);
>   // Expose the 'focusInput' method to the parent component
>   useImperativeHandle(ref, () => ({
>     focusInput: () => {
>       inputRef.current.focus();
>     }
>   }));
>   return (
>     <input
>       ref={inputRef}
>       type="text"
>       placeholder={props.placeholder}
>     />
>   );
> });

export default CustomInput;
In the child component above, we use useRef to create a reference to the input element. Then, with useImperativeHandle, we expose a method called focusInput to the parent component through the ref. This allows the parent component to call focusInput on the child component's ref and focus the input element programmatically.

//Parent Component

import React, { useRef } from 'react';
import CustomInput from './CustomInput';

const ParentComponent = () => {
  const inputRef = useRef(null);

  const handleFocusButtonClick = () => {
    // Call the 'focusInput' method of the child component
    if (inputRef.current) {
      inputRef.current.focusInput();
    }
  };

  return (
    <div>
      {/* Child component with the ref */}
      <CustomInput ref={inputRef} placeholder="Enter your name" />
      <button onClick={handleFocusButtonClick}>Focus Input</button>
    </div>
  );
};

export default ParentComponent;
In the parent component, we use useRef to create a reference (inputRef) that will be used to interact with the child component's focusInput method. When the "Focus Input" button is clicked, the handleFocusButtonClick function will be executed. Inside this function, we call the focusInput method on the child component's ref, which will focus the input element.

This example demonstrates how to use useRef and useImperativeHandle together to create a more controlled interface for interacting with child components from their parent components.

Change the Text of <h1> Element in Child Component using useRef and useImperativeHandle
// Child Component

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

const CustomHeader = forwardRef((props, ref) => {
  const headerRef = useRef(null);

  // Expose the 'changeHeaderText' method to the parent component
  useImperativeHandle(ref, () => ({
    changeHeaderText: (text) => {
      headerRef.current.textContent = text;
    }
  }));

  return (
    <h1 ref={headerRef}>{props.text}</h1>
  );
});

export default CustomHeader;
// Child Component

> import React, { useRef, useImperativeHandle, forwardRef } from 'react';
> const CustomHeader = forwardRef((props, ref) => {
>   const headerRef = useRef(null);
>   // Expose the 'changeHeaderText' method to the parent component
>   useImperativeHandle(ref, () => ({
>     changeHeaderText: (text) => {
>       headerRef.current.textContent = text;
>     }
>   }));
>   return (
>     <h1 ref={headerRef}>{props.text}</h1>
>   );
> });
> export default CustomHeader;
> // Parent component
> import React, { useRef } from 'react';
> import CustomHeader from './CustomHeader';
> const ParentComponent = () => {
>   const headerRef = useRef(null);
>   const handleChangeTextButtonClick = () => {
>     // Call the 'changeHeaderText' method of the child component
>     if (headerRef.current) {
>       headerRef.current.changeHeaderText('New Header Text');
>     }
>   };
>   return (
>     <div>
>       {/* Child component with the ref */}
>       <CustomHeader ref={headerRef} text="Original Header Text" />
>       <button onClick={handleChangeTextButtonClick}>Change Header Text</button>
>     </div>
>   );
> };

In this example, the useRef hook is used in the child component (CustomHeader.js) to create a reference headerRef, which is attached to the <h1> element. The useImperativeHandle hook allows us to expose a method called changeHeaderText to the parent component through the ref. The parent component (ParentComponent) can then use this method to change the text of the <h1> element in the child component without causing a re-render.


**Conclusion**
useRef is a powerful hook in React.js that enables developers to efficiently access and modify DOM elements, preserve values, and manage state without triggering unnecessary re-renders. Its versatility makes it an indispensable tool in a developer's toolkit, allowing for enhanced control and performance optimization in React applications. By mastering the use cases and practical implementations demonstrated in this article, developers can leverage the full potential of useRef to build more robust and efficient React components.