Tutorials Logic, IN info@tutorialslogic.com
Navigation
Home About Us Contact Us Blogs FAQs
Tutorials
All Tutorials
Services
Academic Projects Resume Writing Website Development
Practice
Quiz Challenge Interview Questions Certification Practice
Tools
Online Compiler JSON Formatter Regex Tester CSS Unit Converter Color Picker
Compiler Tools

React Hooks useRef, useMemo, useCallback: Tutorial, Examples, FAQs & Interview Tips

Why These Hooks Matter

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.

Quick Comparison

HookMain purposeTriggers re-render?Common use
useRefStore a mutable value across rendersNoDOM access, previous values, timers
useContextRead shared data from a providerYes, when context value changesTheme, auth user, language
useMemoMemoize a calculated valueNoFiltering, sorting, expensive derived data
useCallbackMemoize a function referenceNoPassing stable handlers to memoized children

useRef

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.

useRef Examples
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

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.

useContext Example
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

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.

useMemo Example
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

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.

useCallback Example
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>
    )
}

How to Choose the Right Hook

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.

Best Practices

SituationRecommended approach
You need to focus or measure a DOM elementUse useRef
You need shared theme or user informationUse useContext
You are repeatedly filtering or sorting a large listUse useMemo if the work is expensive
A memoized child gets a new callback every renderUse useCallback
You are optimizing code before seeing a real issueAvoid premature optimization

Summary

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.

Key Takeaways
  • useRef stores mutable values across renders without causing a re-render.
  • useContext lets deeply nested components read shared data without prop drilling.
  • useMemo caches calculated values when recalculation is expensive.
  • useCallback caches function references and is mainly useful with memoized children.
  • useMemo and useCallback are optimization tools, not default requirements.
  • If changing a value should update the UI immediately, that value usually belongs in state instead of a ref.

Ready to Level Up Your Skills?

Explore 500+ free tutorials across 20+ languages and frameworks.