React Hooks useRef, useMemo, useCallback is an important React JS topic because it appears in real projects, debugging sessions, and interviews. Learn the meaning first, then connect it to a small working example so the rule does not stay abstract.
For this page, focus on what problem React Hooks useRef, useMemo, useCallback solves, where developers usually make mistakes, and how to verify the result. The audit note for this lesson was: limited checklist/practice/mistake/FAQ notes .
A strong understanding of React Hooks useRef, useMemo, useCallback should include syntax, behavior, one realistic use case, one failure case, and one quick way to check your work with tools or output.
React Hooks useRef useMemo useCallback should be studied as a practical React application development lesson, not as a label. Start by naming the input, the rule that changes the input, and the result a learner should be able to predict after reading the page.
In the react-js > hooks-advanced page, the notes should connect the definition with a working scenario, a mistake that beginners actually make, and the exact check that proves the fix. That makes the topic useful for coding, debugging, and interview revision.
Once you understand useState and useEffect, advanced hooks help solve the next group of problems in React applications. They help you keep values across renders, share data deeply in the component tree, and optimize expensive calculations or repeated re-renders.
The important thing is to use each hook for the right job. useRef is not a replacement for state, useContext is not a complete state management library, and useMemo and useCallback are useful only when they solve a real performance problem.
| Hook | Main purpose | Triggers re-render? | Common use |
|---|---|---|---|
| useRef | Store a mutable value across renders | No | DOM access, previous values, timers |
| useContext | Read shared data from a provider | Yes, when context value changes | Theme, auth user, language |
| useMemo | Memoize a calculated value | No | Filtering, sorting, expensive derived data |
| useCallback | Memoize a function reference | No | Passing stable handlers to memoized children |
useRef stores a value that stays the same between renders. Updating a ref does not re-render the component. This makes it useful for remembering values that React does not need to display directly.
The two most common uses of useRef are accessing DOM elements and storing mutable values like timer IDs or previous values.
import { useRef } from 'react'
function FocusInput() {
const inputRef = useRef(null)
const focusField = () => {
inputRef.current.focus()
}
return (
<div>
<input ref={inputRef} placeholder="Type here" />
<button onClick={focusField}>Focus Input</button>
</div>
)
}
import { useRef, useState, useEffect } from 'react'
function PreviousValue() {
const [count, setCount] = useState(0)
const previousCount = useRef(0)
useEffect(() => {
previousCount.current = count
}, [count])
return (
<div>
<p>Current: {count}</p>
<p>Previous: {previousCount.current}</p>
<button onClick={() => setCount(count + 1)}>Increase</button>
</div>
)
}
useContext lets you read shared values without passing props through many levels of components. This is useful when the same data is needed in many places, such as theme, language, or authentication details.
Context works best for shared app-level data. If the data is needed by only one or two nearby components, normal props are often simpler.
import { createContext, useContext, useState } from 'react'
const ThemeContext = createContext(null)
export function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light')
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
)
}
export function useTheme() {
return useContext(ThemeContext)
}
import { useTheme } from './ThemeContext'
function Navbar() {
const { theme, setTheme } = useTheme()
return (
<nav>
<p>Current theme: {theme}</p>
<button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
Toggle Theme
</button>
</nav>
)
}
useMemo stores the result of a calculation so React does not repeat the same expensive work on every render. It is useful when the calculation takes noticeable time or when you want to avoid recreating a derived value unnecessarily.
Do not use useMemo for every small calculation. It is best when the work is expensive enough to justify caching.
import { useState, useMemo } from 'react'
function ProductList({ products }) {
const [search, setSearch] = useState('')
const filteredProducts = useMemo(() => {
return products.filter(product =>
product.name.toLowerCase().includes(search.toLowerCase())
)
}, [products, search])
return (
<div>
<input
value={search}
onChange={(e) => setSearch(e.target.value)}
placeholder="Search products"
/>
<ul>
{filteredProducts.map(product => (
<li key={product.id}>{product.name}</li>
))}
</ul>
</div>
)
}
useCallback stores a function reference so the same function can be reused between renders. This is mainly useful when passing a callback to a memoized child component.
Without useCallback, a new function is created on every render. Sometimes that is completely fine. Use it when a stable function reference actually helps performance or avoids unnecessary child re-renders.
import { useState, useCallback, memo } from 'react'
const ChildButton = memo(function ChildButton({ onClick }) {
console.log('Child rendered')
return <button onClick={onClick}>Increment</button>
})
function Parent() {
const [count, setCount] = useState(0)
const [other, setOther] = useState(0)
const handleIncrement = useCallback(() => {
setCount(prev => prev + 1)
}, [])
return (
<div>
<p>Count: {count}</p>
<p>Other: {other}</p>
<ChildButton onClick={handleIncrement} />
<button onClick={() => setOther(other + 1)}>Update Other</button>
</div>
)
}
Use useRef when you need to remember something without re-rendering. Use useContext when many nested components need the same shared value. Use useMemo when a calculated value is expensive to recompute. Use useCallback when a stable function reference helps a memoized child component.
| Situation | Recommended approach |
|---|---|
| You need to focus or measure a DOM element | Use useRef |
| You need shared theme or user information | Use useContext |
| You are repeatedly filtering or sorting a large list | Use useMemo if the work is expensive |
| A memoized child gets a new callback every render | Use useCallback |
| You are optimizing code before seeing a real issue | Avoid premature optimization |
Advanced hooks help React applications scale more cleanly. useRef remembers mutable values, useContext shares data, useMemo caches calculated values, and useCallback caches function references. Once you understand the purpose of each one, it becomes much easier to choose the right hook for the problem you are solving.
const state = { topic: "React Hooks useRef useMemo useCallback", ready: true };
if (state.ready) {
console.log(state.topic + ": render or run the normal path");
}
const response = null;
const message = response?.message ?? "React Hooks useRef useMemo useCallback: show a clear fallback";
console.log(message);
Memorizing React Hooks useRef useMemo useCallback without the situation where it is useful.
Connect React Hooks useRef useMemo useCallback to a concrete React application development task.
Testing React Hooks useRef useMemo useCallback only with the perfect input.
Include empty, missing, duplicate, incompatible, or failed cases when relevant.
Changing code before reading the visible symptom or error message.
Inspect the output, state, configuration, or stack trace connected to React Hooks useRef useMemo useCallback.
Memorizing React Hooks useRef useMemo useCallback without the situation where it is useful.
Connect React Hooks useRef useMemo useCallback to a concrete React application development task.
The common mistake is memorizing syntax without understanding when the behavior changes or fails.
Remember the problem it solves in React application development, then attach the syntax or steps to that problem.
You can predict the result of a small example, explain a failure case, and choose it over a nearby alternative for a clear reason.
They often copy the syntax but skip the state, input, dependency, selector, route, type, or configuration that controls the behavior.
Explore 500+ free tutorials across 20+ languages and frameworks.