Both useRef and useMemo preserve data between renders, which is why they are often confused. However, they store different things for different reasons.
useRef: a mutable container that doesn't trigger a re-render Think of useRef as a pocket within your component.
It returns a consistent object: `{ current: ... }`. You can modify `current` whenever you like without React triggering a re-render. Its value persists throughout the component's lifecycle. What is it used for?
Accessing the DOM: `const inputRef = useRef(null)` followed by `<input ref={inputRef} />` Storing a mutable value that shouldn't trigger a render: a `setTimeout`, an `intervalId`, the previous render value, or a click counter you don't intend to display. JSX const timerId = useRef(null);
function start() { timerId.current = setInterval(() => console.log("tick"), 1000); } function stop() { clearInterval(timerId.current); } // modifying timerId.current does not trigger a re-render
Show less useRef doesn't perform calculations; it simply stores data.
useMemo: a cache for expensive calculations useMemo is used to avoid unnecessary recalculations.
It executes a function and memoizes (caches) the result. As long as its dependencies remain unchanged, it returns the cached result without re-executing the function. If the dependencies change, it recalculates. This recalculation may trigger a re-render if the result is used within the JSX. JSX const filteredUsers = useMemo(() => { // expensive calculation return users.filter(u => u.name.includes(search)).sort (...); }, [users, search]); You are telling React: "only perform this sort if `users` or `search` changes, not on every render." How do you choose? Do you need to reference a DOM element or remember a value without triggering a re-render? -> `useRef`. Do you have a slow calculation—like a heavy filter, sort, or map—or are you creating an object or array to pass to a memoized component that you don't want to recreate every time? -> `useMemo`. A common pitfall: don't put an expensive calculation inside `useRef` for optimization purposes. `useRef` won't recalculate it when dependencies change, so you'll end up with a stale value. Conversely, don't use `useMemo` to store an `intervalId`, because `useMemo` doesn't guarantee the value will persist indefinitely; React might discard it to free up memory.
Rule of thumb: `useRef` = memory for *you*. `useMemo` = memory for *React*.
👋 Hello! I'm a subscriber. Here is a gift 🐙 and a little tip for making an interesting post: name the mix-up first, then split the two ideas in plain words.