The useRef Hook: When and How to Use It

Published on 12.5.2019

React hooks have brought a new way to work with state, lifecycle methods, and context in functional components, making code more concise and easier to manage. Among these hooks, useRef is one of the lesser-known gems. While it doesn’t directly cause re-renders like useState, it plays a vital role when you need to persist values across renders or directly interact with DOM elements.

In this tutorial, we’ll explore when and how to use the useRef hook. You’ll discover how it can simplify managing focus, tracking values over renders, and manipulating DOM elements.


What Is useRef?

The useRef hook returns a mutable object called a ref. This object has a .current property that can store any mutable value, including DOM nodes or arbitrary data. The key here is that useRef does not trigger a re-render when its value is updated, which is what makes it so powerful.

While useState triggers a component re-render when the state changes, useRef allows us to update its value without re-rendering the component. This makes useRef perfect for cases like managing focus or tracking values that don’t need to cause a re-render.


When to Use useRef

1. Managing Focus

In React, managing focus programmatically (e.g., when you want an input field to gain focus automatically when the page loads) can be tricky, especially if you’re dealing with multiple renders. Instead of using a lifecycle method to do this, useRef can help manage focus without the need for extra re-renders.

Example: Automatically Focus on an Input Field
import React, { useEffect, useRef } from 'react';

function FocusInput() {
  const inputRef = useRef();

  useEffect(() => {
    // Focus the input element on mount
    inputRef.current.focus();
  }, []);

  return <input ref={inputRef} />;
}

export default FocusInput;

Here, the useRef hook stores a reference to the input element, and when the component mounts, useEffect sets the focus to that input field. This all happens without triggering a re-render, ensuring smooth behavior.

2. Tracking Values Over Renders

Sometimes, you might need to store values between renders but don’t want to trigger a re-render when the value changes. useRef can be used to hold onto any mutable value that should persist across renders.

Example: Tracking the Previous Value of a State
import React, { useState, useEffect, useRef } from 'react';

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

  useEffect(() => {
    prevCountRef.current = count;  // Store the previous count
  }, [count]);

  return (
    <div>
      <h1>Current Count: {count}</h1>
      <h2>Previous Count: {prevCountRef.current}</h2>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

export default Counter;

In this example, we use useRef to store the previous count, and it’s updated on every render. The value in prevCountRef.current doesn’t cause a re-render, allowing you to track changes without impacting performance.

3. Accessing DOM Elements Directly

One of the most common uses for useRef is storing a reference to a DOM element. This allows you to manipulate or interact with the DOM directly, such as setting focus, measuring an element, or playing a video. This method is generally used when you need direct access to the DOM rather than relying on React to manage the UI updates.

Example: Accessing a DOM Node for Animation
import React, { useRef } from 'react';

function BoxAnimation() {
  const boxRef = useRef();

  const moveBox = () => {
    boxRef.current.style.transform = 'translateX(100px)';
  };

  return (
    <div>
      <div ref={boxRef} style={{ width: '100px', height: '100px', backgroundColor: 'red' }}></div>
      <button onClick={moveBox}>Move Box</button>
    </div>
  );
}

export default BoxAnimation;

In this case, useRef is used to directly manipulate the DOM node of the red box, and when the button is clicked, we change its position using inline styles. The component doesn’t re-render when the box moves because useRef doesn’t trigger a re-render on updates.


How to Use useRef

Using useRef is quite simple and doesn’t require much boilerplate. Here’s the basic syntax:

const myRef = useRef(initialValue);
  • initialValue: The initial value you want the ref to have. It can be anything—null, an object, a DOM element, etc.
  • myRef.current: The actual value or reference is accessed via .current.

Example: Basic Usage

import React, { useRef } from 'react';

function MyComponent() {
  const myRef = useRef();

  const handleClick = () => {
    console.log(myRef.current); // Logs the DOM element or value stored in the ref
  };

  return (
    <div>
      <button ref={myRef} onClick={handleClick}>Click Me</button>
    </div>
  );
}

export default MyComponent;

Conclusion

useRef is a powerful and flexible hook that lets you manage DOM references and persist values across renders without causing unnecessary re-renders. While useState is perfect for managing state that affects rendering, useRef is the go-to solution when you need to handle things like focus management, tracking previous values, and direct DOM manipulation.

In this post, we’ve looked at when to use useRef and how to integrate it into your React components for cleaner, more efficient code. Whether you’re automating focus or tracking non-UI state, useRef is a must-know tool in the React ecosystem.

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *