React Tutorial 0/120 lessons ~6 min read Lesson 35

    useMemo

    useMemo in React explains caching expensive calculations, dependency arrays, referential stability, and when memoization helps versus when it adds needless complexity.

    Course progress0%
    Focus
    44 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    useMemo is a React Hook that lets you cache the result of a calculation between renders.

    It is primarily useful when a calculation is expensive and does not need to be repeated unless its dependencies change.

    The basic pattern is:

    javascript
    const cachedValue = useMemo(
    () => calculateValue(data),
    [data]
    );

    A useful mental model is:

    text
    Render
    ↓
    Do we already have a cached result
    for the same dependencies?
    │
    ├── Yes → Reuse cached result
    │
    └── No → Calculate → Store result

    useMemo is a performance optimization, not a replacement for correct application logic.

    Why useMemo Exists

    React components can render many times.

    For example:

    javascript
    function ProductList({ products, searchTerm }) {
    const filteredProducts = filterProducts(
    products,
    searchTerm
    );
    return (
    <ul>
    {filteredProducts.map(product => (
    <li key={product.id}>
    {product.name}
    </li>
    ))}
    </ul>
    );
    }

    Every render calls:

    javascript
    filterProducts(products, searchTerm);

    If the calculation is expensive, repeatedly performing it can become costly.

    useMemo allows React to reuse the previously calculated result when its dependencies have not changed:

    javascript
    const filteredProducts = useMemo(
    () => filterProducts(products, searchTerm),
    [products, searchTerm]
    );

    Importing useMemo

    Import it from React:

    javascript
    import { useMemo } from "react";

    It can be used with other Hooks:

    javascript
    import {
    useMemo,
    useState
    } from "react";

    Basic Syntax

    The syntax is:

    javascript
    const value = useMemo(
    () => calculateValue(),
    [dependencies]
    );

    For example:

    javascript
    const total = useMemo(
    () => calculateTotal(items),
    [items]
    );

    The first argument is a function that calculates the value.

    The second argument is the dependency array.

    Understanding the Calculation Function

    Consider:

    javascript
    const total = useMemo(
    () => calculateTotal(items),
    [items]
    );

    The function:

    javascript
    () => calculateTotal(items)

    describes how to calculate the value.

    React can call that function when it needs to produce a new memoized result.

    You do not call the function yourself:

    javascript
    // Incorrect
    useMemo(calculateTotal(items), [items]);

    Instead:

    javascript
    // Correct
    useMemo(() => calculateTotal(items), [items]);

    Understanding Dependencies

    Consider:

    javascript
    const filteredProducts = useMemo(
    () => filterProducts(products, searchTerm),
    [products, searchTerm]
    );

    The calculation depends on:

    text
    products
    searchTerm

    Therefore both are included in the dependency array.

    Mental model:

    text
    products changed?
    OR
    searchTerm changed?
    │
    ▼
    Recalculate
    Neither changed?
    │
    ▼
    Reuse cached value

    React compares dependencies between renders using Object.is semantics.

    A Simple Example

    javascript
    import { useMemo } from "react";
    function Price({ quantity, price }) {
    const total = useMemo(
    () => quantity * price,
    [quantity, price]
    );
    return <p>Total: ₹{total}</p>;
    }

    This example demonstrates the API, but the calculation:

    javascript
    quantity * price

    is extremely cheap.

    Therefore, useMemo is unnecessary here.

    A simpler implementation is better:

    javascript
    function Price({ quantity, price }) {
    const total = quantity * price;
    return <p>Total: ₹{total}</p>;
    }

    This illustrates an important principle:

    Do not add useMemo simply because you can.

    useMemo Is for Optimization

    useMemo should generally be introduced when there is a meaningful performance reason.

    Good candidate:

    javascript
    const visibleProducts = useMemo(
    () => expensiveFilter(products, searchTerm),
    [products, searchTerm]
    );

    Poor candidate:

    javascript
    const fullName = useMemo(
    () => `${firstName} ${lastName}`,
    [firstName, lastName]
    );

    The second calculation is trivial.

    Use:

    javascript
    const fullName = `${firstName} ${lastName}`;

    instead.

    What Does "Memoize" Mean?

    Memoization means remembering the result of a calculation so that it can be reused when the inputs have not changed.

    Conceptually:

    text
    Input
    ↓
    Calculation
    ↓
    Result
    ↓
    Cache

    On a later render:

    text
    Same inputs
    ↓
    Reuse result

    When inputs change:

    text
    Different inputs
    ↓
    Calculate again
    ↓
    Replace cached result

    useMemo and Rendering

    Consider:

    javascript
    function Dashboard({ products, searchTerm }) {
    const filteredProducts = useMemo(
    () => filterProducts(products, searchTerm),
    [products, searchTerm]
    );
    return (
    <div>
    <ProductList products={filteredProducts} />
    </div>
    );
    }

    Suppose the dashboard also has unrelated state:

    javascript
    const [isOpen, setIsOpen] = useState(false);

    If isOpen changes:

    text
    isOpen changes
    ↓
    Dashboard renders
    ↓
    products unchanged
    searchTerm unchanged
    ↓
    useMemo reuses filteredProducts

    The component still renders, but the expensive calculation can be skipped.

    Important:

    useMemo does not prevent the component from rendering.

    It only memoizes the calculation's result.

    useMemo Does Not Prevent Re-Renders

    This is a common misconception.

    Incorrect:

    useMemo stops my component from re-rendering.

    It does not.

    For example:

    javascript
    const result = useMemo(
    () => expensiveCalculation(data),
    [data]
    );

    The component can still render because:

    • Its state changed.
    • Its parent rendered.
    • Its props changed.
    • Context changed.

    useMemo only controls whether the memoized calculation needs to run again.

    useMemo vs React.memo

    These are different tools.

    useMemo

    Memoizes a calculated value:

    javascript
    const filtered = useMemo(
    () => filterItems(items),
    [items]
    );

    React.memo

    Memoizes a component's rendering based on props:

    javascript
    const ProductCard = memo(function ProductCard({
    product
    }) {
    return <div>{product.name}</div>;
    });

    Conceptually:

    text
    useMemo
    ↓
    Memoize a value
    memo
    ↓
    Memoize component rendering

    They can sometimes be used together, but they solve different problems.

    useMemo vs useCallback

    useMemo caches a value:

    javascript
    const result = useMemo(
    () => calculateSomething(data),
    [data]
    );

    useCallback caches a function reference:

    javascript
    const handleClick = useCallback(
    () => doSomething(id),
    [id]
    );

    Mental model:

    text
    useMemo
    → "Remember this calculated value."
    useCallback
    → "Remember this function reference."

    The next lesson covers useCallback in detail.

    useMemo and Referential Equality

    One important reason to use useMemo is maintaining a stable object or array reference when that stability matters.

    Consider:

    javascript
    function Dashboard({ items }) {
    const options = {
    sort: "price",
    limit: 20
    };
    return <ProductList items={items} options={options} />;
    }

    A new object is created on every render.

    Even though its contents are the same:

    text
    Render 1 → options object A
    Render 2 → options object B
    Render 3 → options object C

    If a child relies on reference equality, this can cause unnecessary work.

    You can memoize it:

    javascript
    const options = useMemo(
    () => ({
    sort: "price",
    limit: 20
    }),
    []
    );

    Now React can reuse the same object reference between renders.

    However, do not memoize objects merely because they are objects. There should be a real reason for stable identity.

    useMemo With Child Components

    Suppose:

    javascript
    const ProductList = memo(function ProductList({
    products
    }) {
    return (
    <ul>
    {products.map(product => (
    <li key={product.id}>
    {product.name}
    </li>
    ))}
    </ul>
    );
    });

    If the parent creates a new array every render:

    javascript
    const visibleProducts = products.filter(...);

    the child receives a new array reference.

    Even if the contents are the same, the prop reference changes.

    Using:

    javascript
    const visibleProducts = useMemo(
    () => products.filter(...),
    [products]
    );

    can preserve the same array reference when products has not changed.

    This can make memo more effective.

    Example: Expensive Filtering

    javascript
    import { useMemo, useState } from "react";
    function ProductSearch({ products }) {
    const [searchTerm, setSearchTerm] = useState("");
    const [isDarkMode, setIsDarkMode] = useState(false);
    const filteredProducts = useMemo(() => {
    return products.filter(product =>
    product.name
    .toLowerCase()
    .includes(searchTerm.toLowerCase())
    );
    }, [products, searchTerm]);
    return (
    <div className={isDarkMode ? "dark" : "light"}>
    <input
    value={searchTerm}
    onChange={event =>
    setSearchTerm(event.target.value)
    }
    placeholder="Search products"
    />
    <button
    onClick={() =>
    setIsDarkMode(previous => !previous)
    }
    >
    Toggle Theme
    </button>
    <p>
    Results: {filteredProducts.length}
    </p>
    <ul>
    {filteredProducts.map(product => (
    <li key={product.id}>
    {product.name}
    </li>
    ))}
    </ul>
    </div>
    );
    }

    When the theme changes:

    text
    isDarkMode changes
    ↓
    Component renders
    ↓
    products unchanged
    searchTerm unchanged
    ↓
    filteredProducts reused

    This is a practical use of memoization when filtering is sufficiently expensive.

    Example: Sorting

    Sorting a large dataset can also be expensive.

    javascript
    const sortedProducts = useMemo(() => {
    return [...products].sort(
    (a, b) => a.price - b.price
    );
    }, [products]);

    Notice:

    javascript
    [...products]

    creates a new array before sorting.

    Avoid:

    javascript
    products.sort(...);

    because sort() mutates the array.

    Example: Grouping Data

    Suppose a dashboard groups thousands of transactions:

    javascript
    const transactionsByCategory = useMemo(() => {
    return groupTransactions(transactions);
    }, [transactions]);

    The grouping operation can be reused when unrelated component state changes.

    Example: Expensive Calculation

    javascript
    const result = useMemo(() => {
    return performExpensiveCalculation(
    dataset,
    configuration
    );
    }, [dataset, configuration]);

    If the component re-renders because some unrelated state changes:

    text
    unrelated state
    ↓
    component renders
    ↓
    dataset unchanged
    configuration unchanged
    ↓
    cached result reused

    Dependency Mistakes

    One of the most important rules is to specify the values used by the calculation.

    Consider:

    javascript
    const filtered = useMemo(
    () => filterProducts(products, searchTerm),
    [products]
    );

    The calculation uses:

    text
    products
    searchTerm

    but only products is listed.

    If searchTerm changes, the memoized value may remain stale.

    Prefer:

    javascript
    const filtered = useMemo(
    () => filterProducts(products, searchTerm),
    [products, searchTerm]
    );

    The dependency array should describe the calculation's reactive inputs.

    Empty Dependency Array

    You can write:

    javascript
    const value = useMemo(
    () => expensiveCalculation(),
    []
    );

    This means the calculation has no reactive dependencies.

    However, be careful.

    If the calculation uses values from the component:

    javascript
    const value = useMemo(
    () => expensiveCalculation(data),
    []
    );

    then data is missing from the dependency list.

    Do not use [] simply to force a calculation to happen once.

    Empty Dependencies and Initial Values

    Sometimes developers write:

    javascript
    const config = useMemo(
    () => createConfig(),
    []
    );

    This can be reasonable if the calculation truly has no reactive inputs and the stable reference is useful.

    But for a simple constant, this is unnecessary:

    javascript
    const config = {
    mode: "production"
    };

    Or move a truly static value outside the component:

    javascript
    const config = {
    mode: "production"
    };

    The simplest correct solution is usually best.

    useMemo and Object Dependencies

    Consider:

    javascript
    const options = {
    minPrice,
    maxPrice
    };
    const products = useMemo(
    () => filterProducts(allProducts, options),
    [allProducts, options]
    );

    Because options is recreated on every render, its reference changes every time.

    That can cause the memoized calculation to run every render.

    One solution is to move the object creation into the memo calculation:

    javascript
    const products = useMemo(() => {
    const options = {
    minPrice,
    maxPrice
    };
    return filterProducts(allProducts, options);
    }, [allProducts, minPrice, maxPrice]);

    Now the dependencies represent the actual reactive inputs.

    useMemo Is Not a Semantic Guarantee

    Memoization is an optimization.

    Do not write code that is logically dependent on React preserving a memoized value forever.

    Your application should remain correct even if the calculation is performed again.

    Think:

    text
    useMemo
    ↓
    Potentially skip expensive work

    not:

    text
    useMemo
    ↓
    Guarantee permanent storage

    React may discard memoized values in situations where it needs to.

    Therefore, useMemo should not be used as a substitute for state, refs, or external persistence.

    useMemo Is Not State

    Incorrect:

    javascript
    const selected = useMemo(
    () => calculateSelection(),
    [items]
    );

    and then treating selected as something that can be updated.

    useMemo does not provide a setter.

    It calculates a value from dependencies.

    If the component needs independently changing state:

    javascript
    const [selected, setSelected] = useState(null);

    is appropriate.

    useMemo Is Not an Effect

    Avoid:

    javascript
    const data = useMemo(() => {
    saveToLocalStorage(value);
    return value;
    }, [value]);

    This is mixing side effects into a memoized calculation.

    Use an effect for synchronization:

    javascript
    useEffect(() => {
    localStorage.setItem("value", value);
    }, [value]);

    Use useMemo for calculations.

    Use useEffect for external synchronization.

    useMemo and Pure Calculations

    A good memoized calculation should be pure.

    For example:

    javascript
    const total = useMemo(
    () => calculateTotal(items),
    [items]
    );

    The calculation should:

    • Depend on its inputs.
    • Return a result.
    • Avoid modifying external systems.
    • Avoid mutating input data.
    • Avoid triggering state updates.

    Pure calculations are predictable and easy to memoize.

    Avoid Mutating Inputs

    Incorrect:

    javascript
    const sortedProducts = useMemo(() => {
    return products.sort(
    (a, b) => a.price - b.price
    );
    }, [products]);

    sort() mutates the original array.

    Prefer:

    javascript
    const sortedProducts = useMemo(() => {
    return [...products].sort(
    (a, b) => a.price - b.price
    );
    }, [products]);

    The original state or prop remains unchanged.

    useMemo and Large Lists

    Imagine:

    javascript
    const visibleProducts = useMemo(
    () => products.filter(product => {
    // expensive logic
    }),
    [products, searchTerm, category]
    );

    For a very large list, memoization can reduce repeated filtering when unrelated state changes.

    But if the list contains only a few items, the cost of memoization itself may not be worthwhile.

    The goal is not:

    text
    Use useMemo everywhere

    The goal is:

    text
    Measure or reason about expensive work
    ↓
    Memoize when useful

    useMemo and Performance Measurement

    Before optimizing, identify whether there is an actual performance issue.

    Useful approaches include:

    • React DevTools Profiler
    • Browser performance tools
    • Measuring expensive calculations
    • Observing render behavior
    • Checking real user performance

    Do not optimize based only on assumptions.

    For example:

    javascript
    const fullName = useMemo(
    () => `${firstName} ${lastName}`,
    [firstName, lastName]
    );

    usually adds complexity without solving a meaningful performance problem.

    Common useMemo Mistakes

    Mistake 1: Memoizing Everything

    Avoid:

    javascript
    const name = useMemo(
    () => `${firstName} ${lastName}`,
    [firstName, lastName]
    );

    Prefer:

    javascript
    const name = `${firstName} ${lastName}`;

    Mistake 2: Using useMemo to Prevent Re-renders

    useMemo does not stop the component from rendering.

    It memoizes a calculation's result.

    Mistake 3: Missing Dependencies

    Incorrect:

    javascript
    const result = useMemo(
    () => calculate(data, filter),
    [data]
    );

    Correct:

    javascript
    const result = useMemo(
    () => calculate(data, filter),
    [data, filter]
    );

    Mistake 4: Using useMemo for Side Effects

    Avoid:

    javascript
    useMemo(() => {
    saveData(data);
    }, [data]);

    Use:

    javascript
    useEffect(() => {
    saveData(data);
    }, [data]);

    Mistake 5: Mutating Data During Memoization

    Avoid:

    javascript
    products.sort(...);

    Prefer:

    javascript
    [...products].sort(...);

    Mistake 6: Using useMemo as Persistent Storage

    Do not rely on:

    javascript
    useMemo(...)

    as a permanent storage mechanism.

    Use:

    text
    useState → state
    useRef → mutable persistent value
    external storage → durable persistence

    When Should You Use useMemo?

    Good candidates include:

    Expensive calculations

    javascript
    const result = useMemo(
    () => expensiveCalculation(data),
    [data]
    );

    Large filtering operations

    javascript
    const filtered = useMemo(
    () => filterLargeList(items, search),
    [items, search]
    );

    Expensive sorting

    javascript
    const sorted = useMemo(
    () => [...items].sort(compareItems),
    [items]
    );

    Expensive grouping or transformation

    javascript
    const grouped = useMemo(
    () => groupData(records),
    [records]
    );

    Stable object or array identity

    When a stable reference is actually useful:

    javascript
    const options = useMemo(
    () => ({
    pageSize: 20,
    sortBy: "price"
    }),
    []
    );

    When Should You Not Use useMemo?

    Avoid it for trivial calculations:

    javascript
    const total = price * quantity;
    javascript
    const fullName = `${firstName} ${lastName}`;
    javascript
    const isAdult = age >= 18;

    Also avoid using it just because:

    • A component renders frequently
    • You want every value to be cached
    • You heard memoization improves performance
    • A value is an object
    • A calculation is inside a component

    The performance trade-off should justify the additional complexity.

    A Practical Optimization Example

    Suppose a dashboard contains:

    javascript
    const [search, setSearch] = useState("");
    const [theme, setTheme] = useState("light");

    and processes a large dataset:

    javascript
    const visibleReports = generateReports(
    reports,
    search
    );

    Every theme change causes the component to render, which can repeat:

    javascript
    generateReports(reports, search);

    If report generation is expensive:

    javascript
    const visibleReports = useMemo(
    () => generateReports(reports, search),
    [reports, search]
    );

    Now:

    text
    Theme changes
    ↓
    Dashboard renders
    ↓
    reports unchanged
    search unchanged
    ↓
    Reuse visibleReports

    This is a realistic reason to introduce useMemo.

    useMemo and Child Optimization

    A common optimization chain is:

    text
    useMemo
    ↓
    Stable calculated value
    ↓
    memoized child receives same reference
    ↓
    Child can skip unnecessary render

    Example:

    javascript
    const visibleProducts = useMemo(
    () => filterProducts(products, search),
    [products, search]
    );
    return (
    <ProductList
    products={visibleProducts}
    />
    );

    If ProductList is memoized:

    javascript
    const ProductList = memo(function ProductList({
    products
    }) {
    // ...
    });

    the stable array reference can help it avoid rendering when the list has not logically changed.

    However, this optimization only matters if the child is actually a performance bottleneck.

    useMemo and Derived Data

    Memoized values are still derived data.

    For example:

    javascript
    const total = useMemo(
    () => calculateTotal(items),
    [items]
    );

    The source of truth is still:

    javascript
    items

    The total is derived.

    This is different from storing both:

    javascript
    const [items, setItems] = useState([]);
    const [total, setTotal] = useState(0);

    and synchronizing them with effects.

    A memoized value can be a useful optimization while keeping one source of truth.

    A Useful Optimization Hierarchy

    When a calculation is expensive, consider optimization in this order:

    text
    1. Is the calculation actually expensive?
    ↓
    2. Can the calculation be simplified?
    ↓
    3. Can unnecessary renders be reduced?
    ↓
    4. Can data structures or algorithms improve?
    ↓
    5. Would useMemo provide a measurable benefit?

    Do not start with useMemo automatically.

    Good React performance comes from good component design first.

    useMemo and Algorithmic Complexity

    Memoization cannot fix an inefficient algorithm.

    For example, if:

    javascript
    calculateResults(data);

    takes a long time because it performs unnecessary work, first consider improving the algorithm.

    For example:

    text
    O(n²)
    ↓
    Can it become O(n)?

    An improved algorithm may provide a much larger benefit than caching.

    Then useMemo can be considered if repeated calculation still matters.

    Advanced Example: Expensive Dashboard Statistics

    javascript
    function Dashboard({ transactions }) {
    const statistics = useMemo(() => {
    return {
    total: calculateTotal(transactions),
    average: calculateAverage(transactions),
    categories: groupByCategory(transactions)
    };
    }, [transactions]);
    return (
    <div>
    <p>Total: {statistics.total}</p>
    <p>Average: {statistics.average}</p>
    <CategorySummary
    categories={statistics.categories}
    />
    </div>
    );
    }

    Here multiple calculations depend on the same dataset.

    If these operations are genuinely expensive, memoization can prevent them from repeating when unrelated component state changes.

    Debugging useMemo

    If a memoized calculation runs more often than expected, inspect:

    1. Are dependencies changing?

    For example:

    javascript
    [items, options]

    If options is recreated every render, the memo may invalidate every time.

    2. Are arrays or objects recreated?

    Check reference identity.

    3. Is the calculation actually expensive?

    If not, remove the memoization.

    4. Is a child still rendering?

    Remember that useMemo only memoizes the value. It does not automatically memoize child components.

    5. Are you using memoization to hide an architectural problem?

    Sometimes the better solution is to move state or split components.

    Best Practices

    1. Optimize Based on Need

    Use useMemo when there is a meaningful performance reason.

    2. Keep Calculations Pure

    The callback should calculate and return a value.

    3. Declare Dependencies Correctly

    Include the reactive values used by the calculation.

    4. Avoid Trivial Memoization

    Do not make simple expressions harder to read.

    5. Avoid Mutation

    Create new arrays and objects instead of modifying inputs.

    6. Remember That useMemo Does Not Prevent Rendering

    It only caches a calculation result.

    7. Consider Stable References Carefully

    Memoization can help when reference identity matters, but do not optimize references without a real reason.

    8. Profile Before and After

    Verify that the optimization actually improves performance.

    Interview questions & answers

    Interview preparation

    10 questions grouped by difficulty — expand any card for a model answer and follow-up probe.

    Beginner

    4
    1. 1What is useMemo?
      Beginner

      Model answer

      useMemo is a React Hook that caches the result of a calculation between renders until its dependencies change.
    2. 2What does the dependency array do?
      Beginner

      Model answer

      It tells React which reactive values the calculation depends on. useMemo( → () => calculate(data), → [data] → );
    3. 3Should every expensive-looking calculation use useMemo?
      Beginner

      Model answer

      No.

      Measure or reason about the actual cost and use memoization when it provides a meaningful benefit.

    4. 4Is useMemo a guarantee that React will never recalculate the value?
      Beginner

      Model answer

      No.

      It is a performance optimization, not a semantic guarantee of permanent storage.

    Intermediate

    3
    1. 5Why use useMemo?
      Intermediate

      Model answer

      It can avoid repeating expensive calculations when their inputs have not changed.

    2. 6What is the difference between useMemo and useCallback?
      Intermediate

      Model answer

      useMemo memoizes a calculated value. useCallback memoizes a function reference.
    3. 7Can useMemo be used for side effects?
      Intermediate

      Model answer

      No. Side effects belong in useEffect or event handlers depending on what triggers them.

    Advanced

    3
    1. 8Does useMemo prevent component re-renders?
      Advanced

      Model answer

      No.

      It only memoizes the calculation's result.

    2. 9What is the difference between useMemo and React.memo?
      Advanced

      Model answer

      useMemo memoizes a value inside a component. React.memo can memoize a component so it can skip rendering when its props have not changed.
    3. 10Can useMemo replace useState?
      Advanced

      Model answer

      No. useMemo calculates a value. It does not provide a state setter or independent state transitions.

    Practice Exercises

    Exercise 1: Expensive Calculation

    Create a component that:

    • Receives a large number.
    • Performs an intentionally expensive calculation.
    • Uses useMemo to cache the result.
    • Includes unrelated state to demonstrate when the calculation can be skipped.

    Exercise 2: Product Search

    Create a product search component that:

    • Receives a large product array.
    • Filters products by search term.
    • Uses useMemo.
    • Displays the number of matching products.

    Exercise 3: Product Sorting

    Create a component that:

    • Receives products.
    • Allows sorting by price.
    • Uses useMemo to calculate the sorted list.
    • Does not mutate the original products array.

    Exercise 4: Dashboard Statistics

    Create a dashboard that calculates:

    • Total sales
    • Average sale
    • Number of transactions
    • Sales grouped by category

    Use useMemo for the calculations if they are sufficiently expensive.

    Exercise 5: Stable Options Object

    Create a parent component that passes an options object to a memoized child.

    First observe how a newly created object affects the child.

    Then use useMemo to provide a stable object reference.

    Exercise 6: Remove Unnecessary Memoization

    Take code such as:

    javascript
    const fullName = useMemo(
    () => `${firstName} ${lastName}`,
    [firstName, lastName]
    );

    Refactor it to:

    javascript
    const fullName = `${firstName} ${lastName}`;

    Explain why the second version is preferable.

    Mini Project: Optimized Product Dashboard

    Build a product dashboard with:

    text
    Product list
    Search
    Category filter
    Price sorting
    Theme toggle

    Requirements:

    1. Store search state with useState.
    2. Store category state with useState.
    3. Store sort state with useState.
    4. Filter products.
    5. Sort products.
    6. Use useMemo for genuinely expensive filtering/sorting.
    7. Toggle theme independently.
    8. Demonstrate that changing theme does not require recalculating unchanged product results.

    Example structure:

    javascript
    function ProductDashboard({ products }) {
    const [search, setSearch] = useState("");
    const [category, setCategory] = useState("all");
    const [sortBy, setSortBy] = useState("price");
    const [darkMode, setDarkMode] = useState(false);
    const visibleProducts = useMemo(() => {
    let result = products;
    if (search) {
    result = result.filter(product =>
    product.name
    .toLowerCase()
    .includes(search.toLowerCase())
    );
    }
    if (category !== "all") {
    result = result.filter(
    product => product.category === category
    );
    }
    return [...result].sort((a, b) => {
    if (sortBy === "price") {
    return a.price - b.price;
    }
    return a.name.localeCompare(b.name);
    });
    }, [products, search, category, sortBy]);
    return (
    <div className={darkMode ? "dark" : "light"}>
    {/* Search, filters, sorting and product list */}
    </div>
    );
    }

    The important optimization is:

    text
    darkMode changes
    ↓
    ProductDashboard renders
    ↓
    products/search/category/sort unchanged
    ↓
    visibleProducts reused

    Quick Cheat Sheet

    Import

    javascript
    import { useMemo } from "react";

    Basic usage

    javascript
    const result = useMemo(
    () => calculateValue(data),
    [data]
    );

    Multiple dependencies

    javascript
    const result = useMemo(
    () => calculateValue(data, filter),
    [data, filter]
    );

    Expensive filtering

    javascript
    const filtered = useMemo(
    () => filterProducts(products, search),
    [products, search]
    );

    Expensive sorting

    javascript
    const sorted = useMemo(
    () => [...items].sort(compareItems),
    [items]
    );

    Stable object

    javascript
    const options = useMemo(
    () => ({
    pageSize: 20
    }),
    []
    );

    Avoid unnecessary memoization

    Prefer:

    javascript
    const fullName = `${firstName} ${lastName}`;

    over:

    javascript
    const fullName = useMemo(
    () => `${firstName} ${lastName}`,
    [firstName, lastName]
    );

    Remember

    text
    useMemo
    ↓
    Memoize a value
    useCallback
    ↓
    Memoize a function
    useState
    ↓
    Manage state
    useEffect
    ↓
    Synchronize external systems
    useRef
    ↓
    Persist mutable non-UI values

    Key Takeaways

    Ready to mark this lesson complete?Track your journey across the entire course.