DOM References
DOM References
useRef creates a mutable reference that persists across renders.
Accessing DOM Elements
import { useRef, useEffect } from "react";
function TextInput() {
const inputRef = useRef(null);
useEffect(() => {
// Focus input on mount
inputRef.current.focus();
}, []);
return <input ref={inputRef} type="text" />;
}
ref Callback
function MeasureExample() {
const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
const measureRef = useCallback((node) => {
if (node !== null) {
setDimensions({
width: node.offsetWidth,
height: node.offsetHeight
});
}
}, []);
return (
<div ref={measureRef}>
<p>Width: {dimensions.width}</p>
<p>Height: {dimensions.height}</p>
</div>
);
}
Multiple Refs
function Form() {
const nameRef = useRef(null);
const emailRef = useRef(null);
const passwordRef = useRef(null);
const focusName = () => nameRef.current.focus();
const focusEmail = () => emailRef.current.focus();
const focusPassword = () => passwordRef.current.focus();
return (
<form>
<input ref={nameRef} placeholder="Name" />
<input ref={emailRef} placeholder="Email" />
<input ref={passwordRef} placeholder="Password" />
</form>
);
}
Forwarding Refs
const TextInput = forwardRef((props, ref) => {
return <input ref={ref} {...props} />;
});
function Parent() {
const inputRef = useRef(null);
return (
<div>
<TextInput ref={inputRef} />
<button onClick={() => inputRef.current.focus()}>Focus</button>
</div>
);
}
Mutable Values
Mutable Values
useRef can store any mutable value without causing re-renders.
Storing Timer IDs
function Stopwatch() {
const [time, setTime] = useState(0);
const intervalRef = useRef(null);
const start = () => {
intervalRef.current = setInterval(() => {
setTime((prev) => prev + 1);
}, 1000);
};
const stop = () => {
clearInterval(intervalRef.current);
};
return (
<div>
<p>Time: {time}s</p>
<button onClick={start}>Start</button>
<button onClick={stop}>Stop</button>
</div>
);
}
Previous Values
function Counter() {
const [count, setCount] = useState(0);
const prevCountRef = useRef(0);
useEffect(() => {
prevCountRef.current = count;
}, [count]);
return (
<div>
<p>Current: {count}</p>
<p>Previous: {prevCountRef.current}</p>
</div>
);
}
Storing Values Without Re-render
function Component() {
const renderCountRef = useRef(0);
useEffect(() => {
renderCountRef.current += 1;
});
// This value persists but doesn't cause re-renders
return <p>Rendered {renderCountRef.current} times</p>;
}
Caching Values
function ExpensiveComponent({ data }) {
const cachedResult = useRef(null);
const result = useMemo(() => {
// Expensive computation
return computeExpensiveValue(data);
}, [data]);
// Store in ref for later use
cachedResult.current = result;
}
Avoiding Re-renders
Avoiding Re-renders
When to Use useRef
- Storing timer/interval IDs
- Accessing DOM elements directly
- Storing previous values
- Caching expensive computations
- Storing values that shouldn't trigger re-renders
useRef vs useState
// useState - causes re-render
const [count, setCount] = useState(0);
// useRef - no re-render
const countRef = useRef(0);
Example: Previous Value
function usePrevious(value) {
const ref = useRef();
useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
}
// Usage
function Counter() {
const [count, setCount] = useState(0);
const prevCount = usePrevious(count);
return (
<div>
<p>Now: {count}, Before: {prevCount}</p>
</div>
);
}
Example: Storing Callbacks
function useInterval(callback, delay) {
const savedCallback = useRef();
useEffect(() => {
savedCallback.current = callback;
}, [callback]);
useEffect(() => {
const tick = () => savedCallback.current();
const id = setInterval(tick, delay);
return () => clearInterval(id);
}, [delay]);
}
// Usage
function Timer() {
const [count, setCount] = useState(0);
useInterval(() => {
setCount((c) => c + 1);
}, 1000);
}
Practice Problems
Create a reusable React component implementing useRef. Include proper state management and accessibility.
Solution
// Production-ready component with:
// - Proper TypeScript types
// - Accessibility (ARIA)
// - Error boundaries
// - Loading states
// - Memoization where neededWrite unit and integration tests for useRef using React Testing Library.
Solution
// Test coverage:
// 1. Rendering tests
// 2. Interaction tests
// 3. Edge case tests
// 4. Accessibility testsOptimize useRef for performance. Consider memoization, code splitting, and bundle size.
Solution
// Optimization techniques:
// 1. React.memo / useMemo / useCallback
// 2. Code splitting with lazy()
// 3. Virtual scrolling for lists
// 4. Image lazy loading
// 5. Bundle analysisQuiz
1. What does useRef return?
2. Does changing a ref cause a re-render?
3. When should you use useRef?
4. What is ref forwarding?
Flashcards
Question
What does useRef return?
Click to reveal answer
Answer
An object with a current property
Question
Does changing useRef cause re-renders?
Click to reveal answer
Answer
No, it does not trigger re-renders
Question
What is ref forwarding?
Click to reveal answer
Answer
Passing refs to child components using forwardRef
Question
What is useRef used for?
Click to reveal answer
Answer
DOM access, timers, previous values, mutable storage
Question
What is useRef?
Click to reveal answer
Answer
useRef is a key concept in frontend development.
Revision Notes
Key Takeaways
- 1.useRef returns an object with a current property
- 2.Changing refs doesn't cause re-renders
- 3.Use refs for DOM access and mutable values
- 4.Use forwardRef to pass refs to children
- 5.Refs persist across renders
Interview Tips
- •Explain useRef vs useState
- •Show how to access DOM elements
- •Demonstrate storing previous values
Cheat Sheet
Cheat Sheet
DOM Access
const inputRef = useRef(null);
<input ref={inputRef} />
inputRef.current.focus();
Mutable Storage
const timerRef = useRef(null);
timerRef.current = setInterval(...);
Previous Value
const prevRef = useRef();
useEffect(() => { prevRef.current = value; }, [value]);
return prevRef.current;
Forwarding Refs
const Comp = forwardRef((props, ref) => {
return <input ref={ref} />;
});