useRef in React

In React.js, the useRef hook provides a way to create mutable references to elements or values that persist across renders without causing re-renders. This chapter explores useRef in depth, covering basic usage, advanced techniques, and practical examples to demonstrate its versatility in React applications.

what is useRef ?

The useRef hook is primarily used to persist values across renders without causing re-renders. It returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The .current property persists between renders and can hold any value.

Basic Usage

Let’s begin with a basic example to understand how useRef works.

				
					import React, { useRef } from 'react';

function App() {
  const inputRef = useRef(null);

  const focusInput = () => {
    inputRef.current.focus();
  };

  return (
    <div>
      <input type="text" ref={inputRef} />
      <button onClick={focusInput}>Focus Input</button>
    </div>
  );
}

export default App;

				
			

Explanation:

  • useRef(null) creates a mutable ref object inputRef with an initial value of null.
  • The input element uses ref={inputRef} to assign the ref to the input.
  • focusInput function uses inputRef.current to access the DOM node and calls .focus() to focus the input when the button is clicked.

Output:

When you run this application, you’ll see an input field and a button labeled “Focus Input”. Clicking the button will focus the input field due to the use of inputRef.current.focus().

Practical Examples

Managing Previous State

You can use useRef to store previous values or states without causing re-renders.

				
					import React, { useState, useEffect, useRef } from 'react';

function App() {
  const [count, setCount] = useState(0);
  const prevCountRef = useRef();

  useEffect(() => {
    prevCountRef.current = count;
  });

  const prevCount = prevCountRef.current;

  return (
    <div>
      <p>Current Count: {count}</p>
      <p>Previous Count: {prevCount !== undefined ? prevCount : 'N/A'}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

export default App;

				
			

Explanation:

  • prevCountRef is initialized using useRef().
  • In the useEffect hook, prevCountRef.current is updated with the current count value whenever count changes.
  • prevCount retrieves the previous count from prevCountRef.current and displays it.
  • Clicking the “Increment” button updates the count state, and the previous count is updated accordingly.

Output:

Initially, “Current Count: 0” and “Previous Count: N/A” are displayed. Clicking the “Increment” button updates the current count and shows the previous count.

Using useRef for DOM Measurements

You can use useRef to access DOM measurements or properties directly.

				
					import React, { useRef } from 'react';

function App() {
  const divRef = useRef(null);

  const getDivDimensions = () => {
    if (divRef.current) {
      const { width, height } = divRef.current.getBoundingClientRect();
      alert(`Width: ${width}, Height: ${height}`);
    }
  };

  return (
    <div>
      <div ref={divRef} style={{ width: '200px', height: '100px', background: 'lightblue' }}>
        Resize Me
      </div>
      <button onClick={getDivDimensions}>Get Dimensions</button>
    </div>
  );
}

export default App;

				
			

Explanation:

  • divRef is created using useRef().
  • The div element uses ref={divRef} to assign the ref to the div.
  • getDivDimensions accesses divRef.current to retrieve the getBoundingClientRect() values (width and height) of the div when the button is clicked.

Output:

When you run this application, you’ll see a resizable div element with a button labeled “Get Dimensions”. Clicking the button will alert the width and height of the div element.

Advanced Usage

Imperative DOM Manipulation

You can use useRef for imperative DOM manipulation, such as triggering animations or managing focus.

				
					import React, { useRef } from 'react';

function App() {
  const buttonRef = useRef(null);

  const animateButton = () => {
    if (buttonRef.current) {
      buttonRef.current.classList.add('animate');
      setTimeout(() => {
        buttonRef.current.classList.remove('animate');
      }, 1000);
    }
  };

  return (
    <div>
      <button ref={buttonRef} onClick={animateButton}>
        Animate Me
      </button>
    </div>
  );
}

export default App;

				
			

Explanation:

  • buttonRef is created using useRef().
  • The button element uses ref={buttonRef} to assign the ref to the button.
  • animateButton function accesses buttonRef.current to add and remove the animate class for CSS animations when the button is clicked.

Output:

When you run this application, you’ll see a button labeled “Animate Me”. Clicking the button will trigger a CSS animation defined by the animate class.

Practical Example 1: Managing Focus on Form Inputs

In this example, we will create a form with multiple input fields and use useRef to manage focus between these inputs. This can be useful for improving user experience by automatically focusing the next input when certain conditions are met.

				
					import React, { useRef } from 'react';

function App() {
  const firstNameRef = useRef(null);
  const lastNameRef = useRef(null);
  const emailRef = useRef(null);

  const handleFirstNameKeyPress = (event) => {
    if (event.key === 'Enter') {
      lastNameRef.current.focus();
    }
  };

  const handleLastNameKeyPress = (event) => {
    if (event.key === 'Enter') {
      emailRef.current.focus();
    }
  };

  const handleSubmit = (event) => {
    event.preventDefault();
    alert('Form Submitted!');
  };

  return (
    <div style={{ margin: '20px' }}>
      <h1>Form with Managed Focus</h1>
      <form onSubmit={handleSubmit}>
        <div>
          <label>
            First Name:
            <input
              type="text"
              ref={firstNameRef}
              onKeyPress={handleFirstNameKeyPress}
            />
          </label>
        </div>
        <div>
          <label>
            Last Name:
            <input
              type="text"
              ref={lastNameRef}
              onKeyPress={handleLastNameKeyPress}
            />
          </label>
        </div>
        <div>
          <label>
            Email:
            <input type="email" ref={emailRef} />
          </label>
        </div>
        <div>
          <button type="submit">Submit</button>
        </div>
      </form>
    </div>
  );
}

export default App;

				
			

Explanation:

  • Refs Creation: We create three refs (firstNameRef, lastNameRef, emailRef) using useRef(null) and assign them to the input fields.
  • Focus Management: We handle onKeyPress events on the first two input fields. If the Enter key is pressed, the focus shifts to the next input field using ref.current.focus().
  • Form Submission: A simple form submission handler prevents the default form submission and shows an alert.

Output:

When you run this application, you will see a form with three input fields (First Name, Last Name, and Email). Pressing Enter in the First Name field will automatically focus the Last Name field, and pressing Enter in the Last Name field will focus the Email field. Submitting the form will show an alert.

Practical Example 2: Managing a Timer

In this example, we will create a timer that can be started, stopped, and reset. We will use useRef to store the timer ID to manage the interval properly.

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

function App() {
  const [seconds, setSeconds] = useState(0);
  const timerRef = useRef(null);

  const startTimer = () => {
    if (!timerRef.current) {
      timerRef.current = setInterval(() => {
        setSeconds((prevSeconds) => prevSeconds + 1);
      }, 1000);
    }
  };

  const stopTimer = () => {
    if (timerRef.current) {
      clearInterval(timerRef.current);
      timerRef.current = null;
    }
  };

  const resetTimer = () => {
    stopTimer();
    setSeconds(0);
  };

  return (
    <div style={{ margin: '20px' }}>
      <h1>Timer</h1>
      <p>Seconds: {seconds}</p>
      <button onClick={startTimer}>Start</button>
      <button onClick={stopTimer}>Stop</button>
      <button onClick={resetTimer}>Reset</button>
    </div>
  );
}

export default App;

				
			

Explanation:

  • Timer State: We use useState to keep track of the number of seconds elapsed.
  • Timer Reference: We create a timerRef using useRef(null) to store the timer ID returned by setInterval.
  • Start Timer: startTimer sets up an interval that increments the seconds state every second. It checks if timerRef.current is null to avoid multiple intervals.
  • Stop Timer: stopTimer clears the interval if it exists and resets timerRef.current to null.
  • Reset Timer: resetTimer stops the timer and resets the seconds state to zero.

Output:

When you run this application, you will see a timer display with buttons to start, stop, and reset the timer. Clicking “Start” begins the timer, incrementing the seconds count every second. Clicking “Stop” pauses the timer, and clicking “Reset” stops the timer and resets the count to zero.

The useRef hook in React provides a way to persist mutable values across renders without causing re-renders. It is useful for accessing DOM elements, managing previous states, or imperative DOM manipulations. By understanding and effectively using useRef, you can enhance your React applications with improved performance and maintainability. This chapter covered basic usage, practical examples, and advanced techniques to give you a comprehensive understanding of useRef in React.js.Happy coding !❤️

Table of Contents

Contact here

Copyright © 2025 Diginode

Made with ❤️ in India