React useRef Interview Guide
What is useRef?
Section titled “What is useRef?”useRef is a React Hook that creates a mutable reference object whose value persists across re-renders.
const inputRef = useRef(null);It returns:
{ current: value}Unlike state, updating ref.current does not trigger a re-render.
How useRef Works
Section titled “How useRef Works”flowchart TD
A[Component renders] --> B[useRef creates object once]
B --> C["{ current: initialValue }"]
C --> D[Subsequent renders reuse same object]
D --> E[Updating current does not trigger re-render]
Common Use Cases
Section titled “Common Use Cases”- Accessing DOM elements
- Storing previous values
- Storing mutable values without re-rendering
- Managing timers (
setTimeout/setInterval) - Integrating third-party libraries
Example:
const inputRef = useRef();
useEffect(() => { inputRef.current.focus();}, []);useRef vs useState
Section titled “useRef vs useState”| useRef | useState |
|---|---|
| Doesn’t trigger re-render | Triggers re-render |
| Mutable | Immutable updates |
| Stores reference | Stores UI state |
| Faster for non-UI values | Used for UI updates |
const countRef = useRef(0);
countRef.current++;UI won’t update.
const [count, setCount] = useState(0);
setCount(count + 1);UI updates immediately.
Why Updating ref.current Doesn’t Re-render
Section titled “Why Updating ref.current Doesn’t Re-render”React tracks state changes, not changes to properties on a ref object.
ref.current = 100;The object identity remains the same, so React does not schedule a render.
Persistence Across Renders
Section titled “Persistence Across Renders”const myRef = useRef(0);The same ref object is returned on every render, preserving:
myRef.currentFocusing an Input
Section titled “Focusing an Input”function App() { const inputRef = useRef();
const focusInput = () => { inputRef.current.focus(); };
return ( <> <input ref={inputRef} /> <button onClick={focusInput}>Focus</button> </> );}Storing Previous State
Section titled “Storing Previous State”const [count, setCount] = useState(0);const prevCount = useRef();
useEffect(() => { prevCount.current = count;}, [count]);Usage:
Current: {count}Previous: {prevCount.current}createRef() vs useRef()
Section titled “createRef() vs useRef()”| createRef | useRef |
|---|---|
| Used in Class Components | Used in Functional Components |
| New object each render | Same object every render |
| Less efficient in function components | Preferred |
const ref = createRef(); // new object every renderconst ref = useRef(); // persistent objectAvoiding Unnecessary Re-renders
Section titled “Avoiding Unnecessary Re-renders”const renderCount = useRef(0);
renderCount.current++;Useful for caching values, timers, API request tracking, and counters.
Storing Timer IDs
Section titled “Storing Timer IDs”const timerRef = useRef();
useEffect(() => { timerRef.current = setInterval(() => { console.log("Running"); }, 1000);
return () => clearInterval(timerRef.current);}, []);Initial Values
Section titled “Initial Values”const ref = useRef(10);ref.current === 10The initial value is assigned only once.
Can useRef Replace State?
Section titled “Can useRef Replace State?”No, not for UI state.
Bad:
const countRef = useRef(0);
countRef.current++;Good:
const [count, setCount] = useState(0);Use state whenever UI updates are required.
forwardRef
Section titled “forwardRef”Allows a parent to pass a ref to a child component.
const Input = React.forwardRef((props, ref) => { return <input ref={ref} />;});Parent:
const inputRef = useRef();
<Input ref={inputRef} />useImperativeHandle
Section titled “useImperativeHandle”const Input = forwardRef((props, ref) => { const inputRef = useRef();
useImperativeHandle(ref, () => ({ focus() { inputRef.current.focus(); } }));
return <input ref={inputRef} />;});Parent:
inputRef.current.focus();Preventing Stale Closures
Section titled “Preventing Stale Closures”Problem:
setTimeout(() => { console.log(count);}, 5000);Solution:
const countRef = useRef(count);
useEffect(() => { countRef.current = count;}, [count]);
setTimeout(() => { console.log(countRef.current);}, 5000);Senior-Level Interview Topics
Section titled “Senior-Level Interview Topics”High-Frequency Updates
Section titled “High-Frequency Updates”For mousemove, scroll, drag-and-drop, or WebSocket messages:
Using state:
setPosition(...);causes many re-renders.
Using refs:
positionRef.current = value;avoids rendering overhead.
Behavior During Reconciliation
Section titled “Behavior During Reconciliation”flowchart LR
A[Render] --> B[State updated?]
B -->|Yes| C[React re-renders]
B -->|No| D[Ref object reused]
D --> E[current may change]
E --> F[No render triggered]
const ref = useRef();The object identity survives every render.
useRef vs useMemo
Section titled “useRef vs useMemo”| Hook | Purpose |
|---|---|
useMemo |
Cache expensive computed values |
useRef |
Store mutable persistent values |
const value = useMemo(() => expensiveCalc(), [dep]);const cache = useRef();Memory Leaks
Section titled “Memory Leaks”Refs can contribute to leaks if they retain timers, event listeners, DOM nodes, or large objects without cleanup.
useEffect(() => { const timer = setInterval(() => {}, 1000);
return () => clearInterval(timer);}, []);Real-World Example
Section titled “Real-World Example”const websocketRef = useRef();
websocketRef.current = new WebSocket(url);Useful for:
- WebSocket connections
- WebRTC
- Media players
- Maps SDKs
- Payment SDKs
- Analytics tracking
Choosing the Right Hook
Section titled “Choosing the Right Hook”| Hook | Purpose |
|---|---|
useState |
Store UI state |
useEffect |
Side effects |
useMemo |
Cache expensive calculations |
useCallback |
Cache function references |
useRef |
Store mutable values without re-render |
Common Senior Interview Questions
Section titled “Common Senior Interview Questions”- Why use
useRefinstead ofuseState? - How do you prevent stale closures using refs?
- How do
forwardRefanduseImperativeHandlework together? - How would you optimize a component receiving thousands of events per second using
useRef?
Summary
Section titled “Summary”useRefstores mutable values that persist across renders.- Updating
ref.currentdoes not trigger a re-render. - Use refs for DOM access, timers, caches, previous values, and external object references.
- Use state for UI updates and refs for non-visual mutable data.
- Mastering
forwardRefanduseImperativeHandleis important for advanced React interviews.