Beginner's Guide to React useRef: Understand with Clear, Practical Examples

When working on a React app, have you ever felt like you needed a way to keep track of something without React jumping in and saying, “Hey, let me re-render that for you”? That’s where useRef comes to the rescue. It’s a super handy tool in React’s toolbox, but it’s often misunderstood or underused.

Let’s break it down in a friendly, no-nonsense way.


What Is useRef?

At its core, useRef is a way to store something that persists across renders. It’s like a tiny vault where React doesn’t mess with what’s inside. Here’s why it’s special:

  • It sticks around between renders. Unlike regular variables, the value inside a useRef doesn’t get reset when your component re-renders.

  • It doesn’t trigger re-renders. Changing the value inside a useRef won’t make your component refresh.

  • It gives you direct access to DOM elements. This is perfect for tasks like focusing an input field or scrolling to a specific section of the page.

If React’s useState is like a public noticeboard where every update is announced to everyone, useRef is like a personal notebook where you can jot things down without anyone else noticing.


What Happens If You Don’t Pass an Initial Value to useRef?

When you call useRef() without an initial value, React creates an object with a current property set to undefined:

const ref = useRef();
console.log(ref.current); // undefined

This means ref.current is undefined until you assign something to it. This is handy when you’re not sure what the initial value should be but want to set it later, like storing a DOM element or tracking mutable data.


General Use Cases for useRef

Let’s explore some practical scenarios where useRef shines:

1. Managing Focus or Accessing DOM Elements

Sometimes, you need to directly interact with a DOM element. useRef makes this super easy.

Example: Focusing an Input Field

import React, { useRef } from 'react';

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

  const handleFocus = () => {
    inputRef.current.focus(); // Focus the input element
  };

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

export default FocusInput;

2. Storing Mutable Variables

When you need to keep track of values that don’t affect the UI, useRef is your go-to. This is great for timers, counters, or storing custom data.

Example: Timer

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

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

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

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

  return (
    <div>
      <h1>Time: {seconds}s</h1>
      <button onClick={startTimer}>Start</button>
      <button onClick={stopTimer}>Stop</button>
    </div>
  );
}

export default Timer;

3. Tracking Previous Values

Sometimes, you need to remember what a value was before it changed. useRef can help with that.

Example: Tracking Previous State

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

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

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

  const prevCount = prevCountRef.current;

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

export default PreviousValueTracker;

4. Avoiding Re-renders with Side Effects

When dealing with side effects, such as clearing or resetting timers, useRef ensures your logic runs smoothly without unnecessary re-renders.


What Problems Does useRef Solve?

  • Unnecessary Re-renders: Unlike useState, updates to useRef don’t trigger a component re-render.

  • Performance Optimization: Ideal for storing values that don’t need to affect the UI, like tracking elapsed time or storing custom data.

  • Direct DOM Manipulation: Simplifies tasks like focusing inputs or interacting with scrollable containers.


When NOT to Use useRef

While useRef is powerful, it’s not a magic wand for everything. Avoid using it in these scenarios:

  • UI State Management: If your value affects what’s displayed to the user, use useState. Updates to useRef won’t trigger re-renders, so the UI won’t reflect changes.

  • Complex State Logic: For intricate state relationships, stick with useState or a state management library like Redux.


Quick Tips for Using useRef Effectively

  1. Use useRef for values that change frequently but don’t need to update the UI.

  2. Combine it with useEffect for managing side effects like event listeners or timers.

  3. Avoid overusing useRef for things better suited to state or props.


Wrapping Up

useRef is a powerful tool that can make your React apps more efficient and your life as a developer easier. Whether you’re managing focus, tracking values, or optimizing performance, useRef has your back.

So go ahead, give it a try in your next project, and unlock its potential. You’ll wonder how you ever lived without it!