# Mastering React's useRef Hook


Struggling with values that need to persist between renders but shouldn't trigger UI updates? useRef gives you a stable, mutable container that survives rerenders without causing them.

useRef stores a value in a plain object { current } that React preserves across renders. It's perfect for DOM access, timers, caching, and keeping the "latest" value for event handlers. Read on for practical patterns, code you can copy, and common pitfalls.

## What useRef does (and what it doesn't)

useRef(initialValue) returns an object with a single property: current. React keeps the same object across renders, so you can mutate ref.current freely without causing a rerender.

*   initialValue: used only on the first render.
    
*   ref.current: mutable container you can read/write.
    
*   Does not trigger re-renders when changed — use state for UI updates.
    

One-line summary: useRef gives you a stable, mutable box (ref.current) that persists across renders without re-rendering.

## Basic DOM access (Document Object Model)

When you need a DOM (Document Object Model) node — e.g., to focus an input — useRef is the simplest approach.

```jsx
import { useRef } from 'react';

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

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

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

One-line summary: Attach ref to a DOM node via the ref prop and call ref.current methods like focus().

## Store mutable values that don't affect rendering

Timers, subscription IDs, or any mutable value you don't want to trigger UI can live in refs.

```jsx
import { useEffect, useRef } from 'react';

function Timer() {
  const intervalRef = useRef(null);
  const countRef = useRef(0);

  useEffect(() => {
    intervalRef.current = setInterval(() => {
      countRef.current += 1; // mutate without rerender
    }, 1000);
    return () => clearInterval(intervalRef.current);
  }, []);

  return <div>Timer running (value in ref: {countRef.current})</div>;
}
```

One-line summary: Use refs for timers and other mutable bookkeeping to avoid unnecessary renders.

## Keep the "previous" value

Want the previous prop or state value? Snapshot it into a ref during effect.

```jsx
import { useEffect, useRef } from 'react';

function usePrevious(value) {
  const prevRef = useRef(value);
  useEffect(() => {
    prevRef.current = value;
  }, [value]);
  return prevRef.current;
}
```

One-line summary: Persist prior values across renders by updating ref.current inside an effect.

## Avoiding stale closures: always point to the latest value

Event handlers and effects capture values at creation time. Store the latest value in a ref and read it inside callbacks to avoid stale data.

```jsx
import { useEffect, useRef } from 'react';

function useLatest(value) {
  const ref = useRef(value);
  useEffect(() => {
    ref.current = value;
  });
  return ref;
}

// usage in an interval
function Example({ onTick }) {
  const latestOnTick = useLatest(onTick);

  useEffect(() => {
    const id = setInterval(() => {
      latestOnTick.current(); // always calls latest onTick
    }, 1000);
    return () => clearInterval(id);
  }, [latestOnTick]);
}
```

One-line summary: Store up-to-date callbacks/values in refs to avoid recreating handlers or getting stale closures.

## useRef vs createRef and useState

*   useRef returns a persistent object across renders in function components.
    
*   createRef creates a new ref object every render (usually for class components).
    
*   useState triggers rerenders; use refs when you must avoid rerendering for performance or logic reasons.
    

One-line summary: useRef is the go-to for persistent mutable storage in function components.

## Refs with custom components: forwardRef and useImperativeHandle

You cannot attach a ref to a function component directly unless that component forwards the ref. Use React.forwardRef to expose an inner DOM node or useImperativeHandle to expose a custom API.

```jsx
import React, { forwardRef, useImperativeHandle, useRef } from 'react';

const FancyInput = forwardRef(function FancyInput(props, ref) {
  const inputRef = useRef(null);

  useImperativeHandle(ref, () => ({
    focus: () => inputRef.current?.focus(),
  }));

  return <input ref={inputRef} />;
});

// usage
function Parent() {
  const fancyRef = useRef(null);
  return <button onClick={() => fancyRef.current?.focus()}><FancyInput ref={fancyRef} /></button>;
}
```

One-line summary: Use forwardRef to pass refs to custom components and useImperativeHandle to control the public API.

## Common pitfalls and troubleshooting

*   "My ref didn't update the UI": refs don't trigger renders. Use state for UI changes.
    
*   "I can't get a ref to my component": function components must use forwardRef to accept refs.
    
*   "Initial value ignored": initialValue only applies on first render.
    
*   "Is this safe on the server?": useRef works during server-side rendering; initialValue sets the initial server-rendered value.
    
*   "Using refs for data flow": prefer state and props for the app's data flow; use refs for local, instance-like values.
    

One-line summary: Use refs for local, mutable, instance-like data; don't treat them as state or a substitute for props.

## Quick checklist: when to use useRef

*   You need direct DOM access (focus, selection).
    
*   You store timers, IDs, or mutable counters.
    
*   You want a stable mutable container for the latest callback or value.
    
*   You need to maintain values across renders without causing renders.
    

One-line summary: If the value is an implementation detail that shouldn't affect render output, reach for useRef.

## Conclusion — what to build next

Try converting a component that uses setInterval and state to useRef for the timer and a ref for the latest callback. It will make the component simpler and avoid unnecessary renders.

Next step: open a small sandbox and implement useRef for DOM focus, a timer, and a previous-value hook to get hands-on experience.
