Understanding useRef in React: What It Is and Why It’s Useful

React’s useRef is one of those hooks that seems simple at first, but its power becomes more apparent the more you use it. It allows you to persist values across renders without causing re-renders and gives you a way to directly reference DOM elements.

What is useRef?

useRef is a hook that returns a mutable object with a single property: .current.
This object remains the same between renders — React does not reset it.

Syntax:

const refContainer = useRef(initialValue);
  • refContainer.current is initialized to initialValue.
  • The object persists for the lifetime of the component.

Key Use Cases

  1. Accessing DOM elements directly
    Sometimes you need to manipulate an element without triggering a re-render, like focusing an input.

  2. Storing values that don’t trigger re-renders
    Unlike state (useState), updating .current does not cause the component to render again.

  3. Storing previous values
    You can keep track of a value from the previous render.

Example 1: Accessing DOM Elements

import React, { useRef } from 'react';

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

  const focusInput = () => {
    inputRef.current.focus();
  };

  return (
    <div>
      <input ref={inputRef} type="text" placeholder="Click button to focus me" />
      <button onClick={focusInput}>Focus Input</button>
    </div>
  );
}

What happens?

  • inputRef stores a reference to the <input> DOM element.
  • Calling inputRef.current.focus() sets focus without re-rendering.

Example 2: Storing Values Without Re-render

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

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

  renderCount.current += 1;

  return (
    <div>
      <p>Count: {count}</p>
      <p>Render Count: {renderCount.current}</p>
      <button onClick={() => setCount(count + 1)}>Increase</button>
    </div>
  );
}

What happens?

  • renderCount.current persists across renders.
  • Updating renderCount.current doesn’t trigger a re-render.

Example 3: Tracking Previous State

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

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

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

  return (
    <div>
      <p>Now: {count}, before: {prevCount.current}</p>
      <button onClick={() => setCount(count + 1)}>Increase</button>
    </div>
  );
}

What happens?

  • prevCount.current stores the previous value of count.
  • It updates after each render in useEffect.

Key Takeaways

  • useRef does not cause re-renders when .current changes.
  • Perfect for DOM access, storing non-reactive values, or caching previous data.
  • Works like an instance variable in class components.

Similar Posts