SyntaxStudy
Sign Up
React React.memo for Component Memoisation
React Beginner 1 min read

React.memo for Component Memoisation

React.memo is a higher-order component that wraps a function component and skips re-rendering it if its props have not changed since the last render. React performs a shallow equality check by default, so it works best when props are primitive values or stable object references produced by useMemo or useCallback. You can supply a custom comparison function as the second argument to React.memo when the default shallow check is insufficient — for example when a prop is a deep object and you only care about a subset of its fields. However, writing a custom comparator incorrectly can introduce stale UI bugs that are hard to debug, so prefer restructuring your props to be shallowly comparable instead. React.memo, useMemo, and useCallback form a trio. In a well-optimised subtree, the parent uses useCallback for handlers and useMemo for derived objects it passes down, while the child is wrapped in React.memo. Without all three in place the memoisation breaks: a new function or object reference will still cause the child to re-render.
Example
import React, { useState, useCallback, useMemo } from 'react';

// ── Memoised child ─────────────────────────────────────────────────────────
const UserCard = React.memo(function UserCard({ user, onSelect }) {
    console.log(`Rendering UserCard for ${user.name}`);
    return (
        <div onClick={() => onSelect(user.id)}>
            <strong>{user.name}</strong> — {user.email}
        </div>
    );
});

// ── Custom comparator (compare by id only) ──────────────────────────────────
const HeavyRow = React.memo(
    function HeavyRow({ item }) {
        return <li>{item.label}</li>;
    },
    (prev, next) => prev.item.id === next.item.id
);

// ── Parent ─────────────────────────────────────────────────────────────────
function UserList({ rawUsers, filter }) {
    const [selectedId, setSelectedId] = useState(null);

    const users = useMemo(
        () => rawUsers.filter(u => u.name.includes(filter)),
        [rawUsers, filter]
    );

    const handleSelect = useCallback(id => setSelectedId(id), []);

    return (
        <ul>
            {users.map(u => (
                <UserCard key={u.id} user={u} onSelect={handleSelect} />
            ))}
            {selectedId && <p>Selected: {selectedId}</p>}
        </ul>
    );
}