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.current stores 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

FeatureuseRefuseMemo
PurposeStore mutable value or DOM referenceMemoize computed value for performance
Triggers re-render?NoNo
Common Use CaseAccess DOM, persist value across rendersExpensive calculations, derived data
Syntaxconst 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.