Home/Learn/React/useRef — DOM Access and Values That Do Not Render

useRef — DOM Access and Values That Do Not Render

Intermediate
State & Effects

A ref is a box whose contents survive re-renders and whose changes never cause one. Two uses: reaching a DOM node, and remembering something the UI does not display.

Overview

useRef covers the cases state cannot. Changing a ref does not re-render, which is exactly wrong for anything the user sees and exactly right for a timer id, a previous value, or a flag that only other code reads. The second use is a DOM handle — focusing an input, measuring an element, controlling a video, handing a node to a non-React library. The decision rule is short: if the UI must update when it changes, it is state; if the UI does not care, it is a ref.

DOM Refs

Attach with the ref attribute, use it in effects and handlers, never during render.

ref attribute, and null on first render
function SearchBox() {
  const inputRef = useRef(null)

  useEffect(() => {
    inputRef.current?.focus()        // available after mount
  }, [])

  return <input ref={inputRef} />
}

// current is null during the first render — the DOM does not exist
// yet — so always use optional chaining.

// Real uses: focus management, scrolling into view, measuring,
// play/pause on media, and passing a node to a library.
node.scrollIntoView({ behavior: 'smooth', block: 'nearest' })
const { height } = node.getBoundingClientRect()

// Forwarding a ref to your own component
const Input = forwardRef(function Input(props, ref) {
  return <input ref={ref} {...props} />
})
// In React 19, ref is a normal prop and forwardRef is no longer needed.

Refs as Mutable Boxes

Values that persist across renders without triggering any.

Timer ids, previous values, flags
// A timer id — nothing on screen depends on it
const timerRef = useRef(null)
function start() {
  timerRef.current = setInterval(tick, 1000)
}
function stop() {
  clearInterval(timerRef.current)
}

// The previous value of a prop
const prevStatus = useRef(status)
useEffect(() => { prevStatus.current = status }, [status])

// A "has this already happened" flag that must not re-render
const hasTracked = useRef(false)

// The mistake: using a ref for something the UI displays
const count = useRef(0)
count.current++          // screen never updates — no re-render
// If the user should see it, it is state.

Choosing Between Them

One question, and the escape hatch warning that goes with it.

The decision, and the purity rule
// Does the UI need to update when this changes?
//   yes -> useState
//   no  -> useRef

//              useState              useRef
// re-renders   yes                   no
// read during  safe                  avoid (breaks purity)
//   render
// updates      asynchronous          immediate
//              (next render)         (right now)

// Do not read or write a ref during render:
function Bad() {
  ref.current = ref.current + 1     // impure — breaks with StrictMode,
  return <p>{ref.current}</p>       // concurrent rendering, and reason
}
// Refs belong in effects and event handlers.

// And the wider point: a ref is an escape hatch out of React's model.
// Reaching for one to manipulate the DOM that React manages — hiding
// an element, setting text — means the state model has a gap.

Key Points to Remember

  • 1A ref persists across renders and changing it never triggers one
  • 2ref.current is null during the first render, so DOM access belongs in effects and handlers
  • 3Use a ref for timer ids, previous values and flags — anything the UI does not display
  • 4If the user should see the change, it must be state, not a ref
  • 5Reading or writing a ref during render breaks purity; a ref is an escape hatch, not a state alternative

Interview Questions

Sign in to ask Aria
1

When would you use useRef instead of useState?

Medium
2

Why is ref.current null during the first render?

Medium
3

Why should you not read or write a ref during rendering?

Hard

Ask Aria about useRef — DOM Access and Values That Do Not Render

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…