100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
React

The useRef Hook

Understand how useRef creates a persistent, mutable reference that survives renders without causing re-renders.

Advanced HooksIntermediate10 min readJul 8, 2026
Analogies

Introduction

useRef returns a mutable object with a single .current property that persists for the full lifetime of the component. Unlike state, updating a ref's .current value does not trigger a re-render. This makes useRef useful for two distinct purposes: holding a reference to a DOM node (so you can call imperative APIs like focus() or measure dimensions), and storing any mutable value — a timer ID, a previous prop value, a counter — that needs to survive across renders but should not itself drive the UI.

🏏

Cricket analogy: A ref is like the twelfth man standing by the boundary rope holding a spare bat — always available and swappable without a public announcement (re-render), useful either for a physical prop (the DOM node) or for silently tracking something like the number of drinks breaks taken.

Syntax

jsx
import { useRef } from 'react';

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

  function handleClick() {
    inputRef.current.focus();
  }

  return (
    <>
      <input ref={inputRef} type="text" />
      <button onClick={handleClick}>Focus the input</button>
    </>
  );
}

Explanation

useRef(initialValue) returns an object shaped like { current: initialValue } that React keeps stable across every render — the same object identity is returned each time, only its .current property changes. When you pass a ref object to a JSX element's ref attribute, React sets ref.current to the underlying DOM node after mount and clears it to null on unmount, giving you direct imperative access. The second, equally important use case is as a generic 'instance variable': because reading or writing ref.current never schedules a re-render and its value is not reset between renders, it's the right tool for things like storing a setInterval ID to clear later, tracking whether a component is still mounted, or remembering the previous value of a prop for comparison. Contrast this with useState, where every update triggers a re-render and the value is tied to the rendered UI — refs are explicitly for values that live outside the render/UI cycle.

🏏

Cricket analogy: The same physical scorebook (stable object identity) is used all match, only the ink on the page changes; attaching it to the umpire's stand after the toss and removing it after the match mirrors ref.current being set on mount and cleared on unmount, useful for storing the drinks-break timer ID or the previous over's score for comparison, none of which needs a scoreboard announcement.

Example

jsx
function StopwatchLogger() {
  const intervalRef = useRef(null);
  const tickCountRef = useRef(0);
  const [display, setDisplay] = useState(0);

  function start() {
    if (intervalRef.current !== null) return;
    intervalRef.current = setInterval(() => {
      tickCountRef.current += 1;
      setDisplay(tickCountRef.current);
    }, 1000);
  }

  function stop() {
    clearInterval(intervalRef.current);
    intervalRef.current = null;
  }

  return (
    <div>
      <p>Ticks: {display}</p>
      <button onClick={start}>Start</button>
      <button onClick={stop}>Stop</button>
    </div>
  );
}

Output

Clicking Start begins incrementing tickCountRef.current every second and calling setDisplay so the visible 'Ticks: N' text updates once per second. Notice that tickCountRef itself never causes a re-render when it changes — only the setDisplay call does. intervalRef.current holds the interval ID purely so Stop can clear it later; storing that ID in state instead would cause a pointless extra re-render every time it was set.

🏏

Cricket analogy: Clicking Start begins silently incrementing a private ball-counter (ref) every over while only the public scoreboard update (state) actually redraws the stadium screen once per over; the interval-ID ref just holds the id needed to stop the over-counter later, without itself triggering any screen redraw.

Key Takeaways

  • useRef returns a stable object with a mutable .current property that persists across renders.
  • Changing ref.current does NOT trigger a re-render, unlike useState.
  • Attaching a ref to a JSX element's ref prop gives direct access to the underlying DOM node for imperative operations.
  • Use refs for values that need to persist but shouldn't affect what is rendered, such as timer IDs or previous prop values.
  • Don't read or write ref.current during rendering itself — treat it as an escape hatch used in event handlers and effects.

Practice what you learned

Was this page helpful?

Topics covered

#React#ReactJsStudyNotes#WebDevelopment#TheUseRefHook#UseRef#Hook#Syntax#Explanation#StudyNotes#SkillVeris