useRef
Master useRef — React's hook for values that persist between renders without causing re-renders. Learn DOM access, mutable values, and the patterns that senior engineers use in real applications.
Last reviewed: January 2025
🔍 What Is It?
useRef(initialValue) returns a plain object { current: initialValue }. The object persists for the lifetime of the component. You can read and write ref.current freely — it will not trigger a re-render.
Two main uses:
1. DOM access:
const inputRef = useRef<HTMLInputElement>(null);
<input ref={inputRef} />
inputRef.current?.focus();2. Mutable values without re-render:
const timerRef = useRef<ReturnType<typeof setInterval> | null>(null);
timerRef.current = setInterval(tick, 1000);
clearInterval(timerRef.current);🎯 Why Do We Need It?
Some values need to persist between renders but should not cause re-renders:
- →A timer ID (setInterval/setTimeout) — you need to clear it later, but storing it in state would cause a re-render
- →A previous value (to compare with current)
- →A flag to prevent double-submission or track if a component is still mounted
- →A third-party library instance (Chart.js, Stripe, maps)
And sometimes you need to interact with the actual DOM node — something React's virtual DOM intentionally abstracts away but occasionally you need to bypass: focus management, scroll position, canvas drawing, integrating non-React libraries.
🏗️ What Happens in Real Projects?
In a real banking application:
- →Focus the first invalid form field after submission attempt
- →Store a WebSocket instance and close it on unmount
- →Track whether a payment form has been submitted (prevent double-submit)
- →Store the previous account balance to animate the difference
- →Hold a Chart.js instance for a spending trend chart
- →Scroll a message list to the bottom when new messages arrive
⚙️ How It Works
React creates the { current } object once and returns the same object on every render. When you write ref.current = newValue, you are mutating the object directly — React does not know about this change and does not re-render.
DOM refs:
When you pass a ref to a JSX element's ref prop, React sets ref.current to the DOM node after mounting, and sets it back to null after unmounting. The DOM node is available in useEffect (after render) but not during render.
Forwarding refs:
To pass a ref through a custom component to its inner DOM element, use React.forwardRef. This is essential for design system components.
💻 Example
useRef Patterns in Production — DOM access, mutable values, and the previous-value pattern.
🤔 Common Confusions
❓ When should I use useRef vs useState?
Use useState when the value change should trigger a UI update (re-render). Use useRef when the value change should NOT trigger a re-render: timer IDs, previous values, DOM nodes, flags, third-party library instances. If you are not sure, start with useState. If you find yourself thinking "I need this value but I do not want a re-render", that is useRef.
❓ Can I read ref.current during render?
For DOM refs, no — the DOM does not exist during render, so ref.current is null. For mutable value refs, technically yes, but it is a code smell. Refs are for values accessed in event handlers and effects, not during render. If you need a value during render, use state.
❓ Why does my ref.current show null on first render?
DOM refs are null during render because the DOM does not exist yet. React sets ref.current to the DOM node after the component mounts. Access DOM refs inside useEffect (runs after mount) or event handlers (triggered after mount), never during render.
🚨 Common Production Issues
**Bug: Reading DOM ref during render** — ref.current is null during render. Access DOM refs in useEffect or event handlers only.
**Bug: Forgetting to clean up** — Storing a timer or subscription in a ref and forgetting to clear it in useEffect cleanup causes memory leaks.
**Misuse: Using ref instead of state for UI values** — If a value should update the UI when it changes, it must be state. Refs do not trigger re-renders.
**Misuse: Forwarding refs manually** — Passing a ref as a regular prop (not using React.forwardRef) does not work. React has special handling for the ref prop.
✅ Best Practices
Use TypeScript generics for typed refs: useRef<HTMLInputElement>(null)
Always initialise DOM refs with null: useRef<HTMLElement>(null)
Use optional chaining when accessing DOM refs: ref.current?.focus()
Clean up timers and subscriptions stored in refs inside useEffect cleanup
Use React.forwardRef to expose refs from custom components in design systems
Prefer useRef over a module-level variable for instance-specific mutable values
🏛️ Architect's Note
useRef is the correct tool when you need to "step outside" React's rendering model. The key insight: React owns the virtual DOM and state. Sometimes you need to interact with the real DOM (accessibility, animations, third-party libs) or store values that are truly implementation details of a component (timers, flags). useRef is the bridge. Use it deliberately and document why — a ref in the codebase is a signal that something non-standard is happening.
💬 Frequently Asked Questions
🎯 Key Takeaways
🔗 Related Topics
🎯 Practice this topic in interviews
↗ Where this topic fits
React Technology Guide
Return to the React learning hub.
Frontend Engineer Career Path
A beginner-friendly journey through web foundations, React, production frontend engineering, and interview preparation.
Python Developer Career Path
A practical route through Python fundamentals, automation, backend basics, testing, projects, interview preparation, and career growth.
Sources
Sources / References
Use these React references to verify the concept in official docs and continue into the most relevant SplashRide pages.
Official documentation
Related SplashRide pages
SplashRide React learning path
Browse the full React topic collection and learning order on SplashRide.
React Interview Prep
Practice React interview questions and scenario-based answers.
Frontend Engineer Career Path
A beginner-friendly journey through web foundations, React, production frontend engineering, and interview preparation.
Python Developer Career Path
A practical route through Python fundamentals, automation, backend basics, testing, projects, interview preparation, and career growth.
useState
Master useState — the most fundamental React hook. Learn how it works under the hood, the patterns senior engineers use, and the bugs that trip up even experienced developers.
useEffect
Master useEffect — the hook for synchronising React components with the outside world. Learn the dependency array, cleanup functions, and how to avoid the most common production bugs.