React useRef Hook Explained with Real Examples and Best Practices 2025 guide bilal shafqat

React useRef Hook Explained with Real Examples and Best Practices (2025 Guide)

Learn what the React useRef() hook does, when to use it, and how it compares to useState(). Includes real-world examples for DOM access, value tracking, and performance optimizations.

Introduction: What is useRef in React?

If you’re working with React functional components, you’ve probably used useState() and useEffect() — but what about useRef()?

React’s useRef() hook is a powerful yet often underutilized tool. While it’s commonly associated with accessing DOM elements, it’s much more versatile than that.

In this guide, you’ll learn:

  • What useRef() is
  • When and why to use it
  • How it differs from useState()
  • Real examples including DOM access, persisting values, and timers
  • Common mistakes to avoid
  • Best practices for 2025 and beyond

What is useRef?

useRef() is a built-in React hook that returns a mutable object with a .current property. Unlike state, updating this .current value does not trigger a re-render.

Syntax:

const ref = useRef(initialValue);

What it returns:

{
  current: initialValue
}

This ref object persists for the entire lifetime of the component.

When to Use useRef()

1. Accessing DOM Elements

This is the most well-known use case — directly referencing a DOM node for actions like focusing an input or scrolling.

2. Persisting Values Across Renders

You can store a value in a ref that will survive re-renders without causing the component to update.

3. Storing Previous Props or State

Refs are perfect for tracking what a value was during the previous render — without triggering another render.

4. Timer IDs or Animation References

If you’re using setTimeout, setInterval, or animations, useRef() lets you store IDs cleanly.

Example 1: Focus an Input Field

import { useRef } from 'react';

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

  return (
    <>
      <input ref={inputRef} />
      <button onClick={() => inputRef.current.focus()}>
        Focus Input
      </button>
    </>
  );
}

In this example:

  • useRef() creates a reference object.
  • React assigns that object to the ref attribute.
  • On button click, you call .focus() on the DOM node.

Example 2: Tracking Previous State

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

function Counter() {
  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)}>Increment</button>
    </>
  );
}

This setup tracks the previous count value without triggering any extra renders.

useRef vs useState: What’s the Difference?

Feature useRef useState
Triggers re-render No Yes
Persists across renders Yes Yes
DOM access Yes No
UI state updates No Yes
Use for DOM, timers, previous values User-facing state

Common Mistakes to Avoid with useRef

Mistake 1: Using ref for data that should trigger a re-render

If your UI depends on a value, it should be stored in state — not ref.

Bad:

const countRef = useRef(0);
countRef.current += 1;

Better:

const [count, setCount] = useState(0);
setCount(count + 1);

Mistake 2: Forgetting that useRef doesn’t cause a re-render

Changing .current won’t make the component update. This is both a feature and a gotcha.

Mistake 3: Assuming useRef is only for DOM

Refs can hold anything — not just DOM elements. Think of it as a safe, persistent container.

Best Practices for useRef in 2025

  • Use it to hold mutable values you don’t want to trigger a render
  • Use it to reference DOM nodes for animations or focus behavior
  • Combine with useEffect() to track previous props or state
  • Use it to store timers or animation frame IDs
  • Avoid overusing it where useState() or useReducer() are better fits

Real-World Use Cases

Accessing a scrollable container:

const scrollRef = useRef();
scrollRef.current.scrollTop = 0;

Controlling a video player:

videoRef.current.play();

Tracking if component is mounted:

const isMounted = useRef(false);

useEffect(() => {
  isMounted.current = true;
  return () => {
    isMounted.current = false;
  };
}, []);

Should I Use useRef or useMemo?

useRef() is for storing mutable values, like DOM nodes or internal variables.

useMemo() is for memoizing computed values to prevent unnecessary recalculations.

Use useRef when:

  • You need to store a DOM node
  • You need a stable reference that persists between renders
  • You’re tracking internal mutable state that doesn’t affect UI

Use useMemo when:

  • You’re calculating a value that should be cached
  • You want to optimize expensive logic that runs every render

Summary: useRef() in React

useRef() is a flexible, persistent container inside your component. It’s ideal for:

  • Managing focus and scrolling
  • Tracking previous values
  • Holding timers or animation IDs
  • Avoiding unnecessary re-renders

Just remember: useRef() is not reactive — changing .current does not trigger re-renders.

Use it for logic and side effects, not for data that needs to appear in the UI.

Learn More

Want to dive deeper into hooks like useState, useEffect, and useContext?

Leave A Comment