Files
2026-04-10 16:50:03 +07:00

1.8 KiB

title, impact, impactDescription, tags
title impact impactDescription tags
Split Combined Hook Computations MEDIUM avoids recomputing independent steps rerender, useMemo, useEffect, dependencies, optimization

Split Combined Hook Computations

When a hook contains multiple independent tasks with different dependencies, split them into separate hooks. A combined hook reruns all tasks when any dependency changes, even if some tasks don't use the changed value.

Incorrect (changing sortOrder recomputes filtering):

const sortedProducts = useMemo(() => {
  const filtered = products.filter((p) => p.category === category);
  const sorted = filtered.toSorted((a, b) =>
    sortOrder === 'asc' ? a.price - b.price : b.price - a.price
  );
  return sorted;
}, [products, category, sortOrder]);

Correct (filtering only recomputes when products or category change):

const filteredProducts = useMemo(
  () => products.filter((p) => p.category === category),
  [products, category]
);

const sortedProducts = useMemo(
  () =>
    filteredProducts.toSorted((a, b) =>
      sortOrder === 'asc' ? a.price - b.price : b.price - a.price
    ),
  [filteredProducts, sortOrder]
);

This pattern also applies to useEffect when combining unrelated side effects:

Incorrect (both effects run when either dependency changes):

useEffect(() => {
  analytics.trackPageView(pathname);
  document.title = `${pageTitle} | My App`;
}, [pathname, pageTitle]);

Correct (effects run independently):

useEffect(() => {
  analytics.trackPageView(pathname);
}, [pathname]);

useEffect(() => {
  document.title = `${pageTitle} | My App`;
}, [pageTitle]);

Note: If your project has React Compiler enabled, it automatically optimizes dependency tracking and may handle some of these cases for you.