React useRef Explained Real-World Examples for Beginners and Pros

React useRef Explained: Real-World Examples for Beginners and Pros

Introduction

When you think of React, you usually think about state, props, and re-rendering. But sometimes you just need a way to:

  • Grab a DOM element directly
  • Store a value without causing a re-render
  • Keep track of something between renders

That’s exactly where the useRef hook comes in.

In this post, I’ll explain useRef like I would to a teammate, and we’ll go over practical examples you’ll actually use in the real world.

What Is useRef?

useRef is a React Hook that gives you a mutable object that doesn’t trigger re-renders when updated.

const myRef = useRef(initialValue);
  • It returns an object like { current: value }
  • You can update myRef.current = newValue
  • The value persists across renders
  • It does not cause a re-render when it changes

useRef for Accessing DOM Elements

The most common use case: grabbing DOM nodes.

Let’s say you want to auto-focus an input field when a component loads.

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

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

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

  return <input ref={inputRef} placeholder="Type to search..." />;
}
What’s Happening?
  • inputRef.current gives us the DOM element.
  • We can now call native methods like .focus(), .scrollIntoView(), etc.

This is super helpful in:

  • Login forms
  • Modals
  • Chat apps
  • Search UIs

useRef to Store Mutable State (That Doesn’t Re-render)

Sometimes you want to keep a value without triggering re-renders.

Here’s an example of a timer using setInterval:

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

function Timer() {
  const [count, setCount] = useState(0);
  const intervalRef = useRef();

  useEffect(() => {
    intervalRef.current = setInterval(() => {
      setCount((prev) => prev + 1);
    }, 1000);

    return () => clearInterval(intervalRef.current);
  }, []);

  return <h1>Time: {count}s</h1>;
}
Why Not useState for interval?

Because useState would re-render every time we store the timer ID.
useRef keeps it safely stored without causing unnecessary re-renders.

useRef to Track Previous Values

Another practical trick — track the previous value of a prop or state.

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

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

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

  return (
    <div>
      <p>Current: {count}</p>
      <p>Previous: {prevCount.current}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

This is super helpful in:

  • Animations
  • Comparing prop/state changes
  • Building undo/redo features

useRef vs useState — When to Use What?

ScenariouseRefuseState
Needs to persist across rendersYesYes
Triggers a re-render when changedNoYes
Stores a DOM node referenceYesNo
Tracks a value but shouldn’t re-render UIYesNo
Rule of Thumb:

Use useRef when you need to remember something but don’t want it to affect rendering.


Bonus: useRef in Form Validation

Let’s say you’re checking input field validity on form submit:

function LoginForm() {
  const usernameRef = useRef();
  const passwordRef = useRef();

  const handleSubmit = (e) => {
    e.preventDefault();
    const username = usernameRef.current.value;
    const password = passwordRef.current.value;

    if (!username || !password) {
      alert("Both fields are required!");
    } else {
      alert(`Welcome, ${username}!`);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <input ref={usernameRef} placeholder="Username" />
      <input ref={passwordRef} type="password" placeholder="Password" />
      <button type="submit">Login</button>
    </form>
  );
}

No need for extra useState if you’re not updating the UI based on input changes.

What useRef Is Not For

  • It’s not a state replacement for anything that changes the UI
  • It won’t notify React when updated
  • You shouldn’t use it for things like “show/hide UI”

Summary

useRef lets you:

  • Access DOM nodes (like .focus())
  • Store timers or values across renders
  • Keep previous values
  • Build more optimized components

It’s one of those quiet heroes in React—once you really get it, you’ll use it everywhere (for the right reasons).