React

Lesson 09

Memoization when it helps

Use memoization for repeated expensive work with correct dependencies, not as decoration.

Good Code

ReviewSearch.tsx
import { useMemo } from "react";

type Review = {
  id: string;
  title: string;
  authorName: string;
};

function matchesSearch(review: Review, search: string) {
  const query = search.toLowerCase();
  return (
    review.title.toLowerCase().includes(query) ||
    review.authorName.toLowerCase().includes(query)
  );
}

export function ReviewSearch({
  reviews,
  search,
}: {
  reviews: Review[];
  search: string;
}) {
  // Memoization is tied to the expensive list calculation inputs.
  const visibleReviews = useMemo(
    () => reviews.filter((review) => matchesSearch(review, search)),
    [reviews, search],
  );

  return (
    <ul>
      {visibleReviews.map((review) => (
        <li key={review.id}>{review.title}</li>
      ))}
    </ul>
  );
}

Bad Code

ReviewSearch.tsx
import { useMemo } from "react";

type Review = {
  id: string;
  title: string;
  authorName: string;
};

function matchesSearch(review: Review, search: string) {
  return review.title.toLowerCase().includes(search.toLowerCase());
}

export function ReviewSearch({
  reviews,
  search,
}: {
  reviews: Review[];
  search: string;
}) {
  // Empty dependencies freeze the list after the first render.
  const visibleReviews = useMemo(
    () => reviews.filter((review) => matchesSearch(review, search)),
    [],
  );
  const resultLabel = useMemo(
    () => "Showing " + visibleReviews.length + " reviews",
    [visibleReviews.length],
  );

  return (
    <>
      <p>{resultLabel}</p>
      <ul>
        {visibleReviews.map((review) => (
          <li key={review.id}>{review.title}</li>
        ))}
      </ul>
    </>
  );
}

Review Notes

What to review

Good Code

The good version memoizes a filtered list and lists the inputs that affect that list.

Bad Code

The bad version memoizes the list with an empty dependency array, so the UI can ignore new reviews or search text. It also memoizes a cheap label that does not need caching.

Takeaways

  • Memoization should have a clear cost to avoid and a complete dependency list.