Homepage (site/index.html): integration-v14 promoted, Writings section integrated with 33 pieces clustered by type (stories/essays/miscellany), Writings welcome lightbox, content frame at 98% opacity. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
65 lines
1.8 KiB
Markdown
65 lines
1.8 KiB
Markdown
---
|
|
title: Split Combined Hook Computations
|
|
impact: MEDIUM
|
|
impactDescription: avoids recomputing independent steps
|
|
tags: 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):**
|
|
|
|
```tsx
|
|
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):**
|
|
|
|
```tsx
|
|
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):**
|
|
|
|
```tsx
|
|
useEffect(() => {
|
|
analytics.trackPageView(pathname)
|
|
document.title = `${pageTitle} | My App`
|
|
}, [pathname, pageTitle])
|
|
```
|
|
|
|
**Correct (effects run independently):**
|
|
|
|
```tsx
|
|
useEffect(() => {
|
|
analytics.trackPageView(pathname)
|
|
}, [pathname])
|
|
|
|
useEffect(() => {
|
|
document.title = `${pageTitle} | My App`
|
|
}, [pageTitle])
|
|
```
|
|
|
|
**Note:** If your project has [React Compiler](https://react.dev/learn/react-compiler) enabled, it automatically optimizes dependency tracking and may handle some of these cases for you.
|