React useRef & useMemo Hooks: Beginner’s Guide with Examples
React Hooks like useRef and useMemo are essential for advanced functional component behavior.
useRef → Access DOM elements directly and persist values across renders without causing re-renders.
useMemo → Optimize performance by memoizing expensive computations and preventing unnecessary recalculations.
Both are useful for efficient and interactive React apps.
useRef Hook
useRef allows you to:
Store a mutable value that does not trigger re-render
Access DOM elements directly
Syntax
const refContainer = useRef(initialValue); refContainer.currentstores the value or DOM reference.
Example 1: Accessing DOM Element
import { useRef } from "react";
function InputFocus() {
const inputRef = useRef(null);
const handleFocus = () => {
inputRef.current.focus();
};
return (
<div>
<input ref={inputRef} type="text" placeholder="Type here..." />
<button onClick={handleFocus}>Focus Input</button>
</div>
);
}
Clicking the button focuses the input without re-rendering the component.
Example 2: Persisting Values Across Renders
import { useRef, useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
const renderCount = useRef(0);
renderCount.current += 1;
return (
<div>
<p>Count: {count}</p>
<p>Component rendered: {renderCount.current} times</p>
<button onClick={() => setCount(count + 1)}>Increase</button>
</div>
);
}
renderCount.current persists across renders without triggering re-render.
useMemo Hook
useMemo is used to memoize expensive calculations to avoid recalculating on every render.
Syntax
const memoizedValue = useMemo(() => computeValue(a, b), [a, b]); First argument → function that returns the value
Second argument → dependency array, runs computation only when dependencies change
Example 1: Expensive Calculation
import { useState, useMemo } from "react";
function ExpensiveComponent() {
const [count, setCount] = useState(0);
const [text, setText] = useState("");
const expensiveCalculation = (num) => {
console.log("Calculating...");
for (let i = 0; i < 1000000000; i++) {} // heavy computation
return num * 2;
};
const double = useMemo(() => expensiveCalculation(count), [count]);
return (
<div>
<p>Count: {count}</p>
<p>Double: {double}</p>
<button onClick={() => setCount(count + 1)}>Increase Count</button>
<input
type="text"
value={text}
onChange={(e) => setText(e.target.value)}
placeholder="Type here..."
/>
</div>
);
}
Without useMemo, typing in the input would re-run the expensive calculation unnecessarily.
Key Differences: useRef vs useMemo
| Feature | useRef | useMemo |
|---|---|---|
| Purpose | Store mutable value or DOM reference | Memoize computed value for performance |
| Triggers re-render? | No | No |
| Common Use Case | Access DOM, persist value across renders | Expensive calculations, derived data |
| Syntax | const ref = useRef(initialValue) | const memoValue = useMemo(() => compute(), [deps]) |
Best Practices
useRef
Use for DOM access or mutable values that don’t need rendering.
Avoid using ref to store stateful data that affects UI.
useMemo
Use only for expensive calculations.
Don’t overuse — unnecessary memoization can hurt performance.
Combine with dependencies carefully to prevent stale values.
FAQ
Q1: Can useRef trigger re-render?
No, changing ref.current does not re-render the component.
Q2: Can useMemo replace useState?
No, useMemo is for computations, not storing state.
Q3: Can I use useRef for timers or subscriptions?
Yes! useRef is perfect for keeping track of intervals or external IDs.