DEV Community

Cover image for Understanding useRef in React: Concepts, Use Cases, and Examples
Vinayagam
Vinayagam

Posted on

Understanding useRef in React: Concepts, Use Cases, and Examples

Understanding useRef in React (Beginner Friendly Guide)

React provides several hooks to manage state and behavior in functional components. One of the most commonly misunderstood hooks is useRef. While it looks simple, it solves important problems related to rendering and DOM interaction.

This blog explains useRef with clear concepts, practical examples, and when to use it correctly.


What is useRef?

useRef is a React Hook that returns a mutable object with a .current property.

const ref = useRef(initialValue);
Enter fullscreen mode Exit fullscreen mode

This object persists for the entire lifetime of the component.


Key Characteristics of useRef

  • Stores a value that does not trigger re-render
  • Keeps the same reference across renders
  • Can directly access DOM elements
  • Works like a container that holds mutable data

How useRef Works Internally

When you write:

const myRef = useRef(10);
Enter fullscreen mode Exit fullscreen mode

React internally creates an object like:

{
  current: 10
}
Enter fullscreen mode Exit fullscreen mode

Important points:

  • This object is not recreated on every render
  • Only the .current value changes
  • React does not track changes inside .current

Why useRef is Needed

React components re-render when state or props change. However, not all data changes should trigger a re-render.

There are two main problems useRef solves:

1. Avoid unnecessary re-renders

Using useState for every value can cause performance issues.

2. Direct DOM manipulation

React is declarative, but some cases require imperative control (like focusing an input).


Accessing DOM Elements

import { useEffect, useRef } from "react";

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

  useEffect(() => {
    inputRef.current.focus();
  }, []);

  return <input ref={inputRef} />;
}
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • ref attribute connects the DOM element to inputRef
  • inputRef.current gives direct access to the DOM node
  • The focus method is called after render

Persisting Values Without Re-render

import { useRef } from "react";

function App() {
  const countRef = useRef(0);

  const handleClick = () => {
    countRef.current += 1;
    console.log(countRef.current);
  };

  return <button onClick={handleClick}>Click</button>;
}
Enter fullscreen mode Exit fullscreen mode

Here:

  • Value updates
  • Component does not re-render
  • Useful for storing non-UI data

Tracking Previous State

import { useEffect, useRef, useState } from "react";

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

  useEffect(() => {
    prevCount.current = count;
  }, [count]);

  return (
    <>
      <p>Current: {count}</p>
      <p>Previous: {prevCount.current}</p>
      <button onClick={() => setCount(count + 1)}>Increase</button>
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

This pattern is useful when comparing previous and current values.


Working with Timers

import { useRef } from "react";

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

  const start = () => {
    timerRef.current = setInterval(() => {
      console.log("Running...");
    }, 1000);
  };

  const stop = () => {
    clearInterval(timerRef.current);
  };

  return (
    <>
      <button onClick={start}>Start</button>
      <button onClick={stop}>Stop</button>
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

useRef helps store the interval ID across renders.


useRef vs useState (Conceptual Difference)

Concept useState useRef
Triggers re-render Yes No
Data visibility Used in UI Not directly used in UI
Mutability Immutable updates required Mutable (.current can change)
Lifecycle behavior Re-initialized logically Persisted across renders

When to Use useRef

Use useRef when:

  • You need direct access to a DOM element
  • You want to store mutable data without re-render
  • You need to persist values between renders
  • You are working with timers, intervals, or external libraries

When Not to Use useRef

Avoid using useRef when:

  • The value should be visible in UI
  • UI must update when value changes
  • State management is required

In these cases, useState is the correct choice.


Common Mistakes

1. Forgetting .current

inputRef.focus(); // incorrect
Enter fullscreen mode Exit fullscreen mode

Correct:

inputRef.current.focus();
Enter fullscreen mode Exit fullscreen mode

2. Using useRef for UI updates

Changing .current will not update the UI.


3. Expecting reactivity

useRef is not reactive like state.


Mental Model

  • useState → reactive data (affects UI)
  • useRef → persistent container (does not affect UI)

Top comments (0)