65 lines
1.8 KiB
Markdown
65 lines
1.8 KiB
Markdown
---
|
||
title: 拆分组合的 Hook 计算
|
||
impact: MEDIUM
|
||
impactDescription: 避免重新计算独立的步骤
|
||
tags: rerender, useMemo, useEffect, dependencies, optimization
|
||
---
|
||
|
||
## 拆分组合的 Hook 计算
|
||
|
||
当一个 Hook 包含多个具有不同依赖项的独立任务时,应将它们拆分为单独的 Hook。组合式的 Hook 在任意依赖项发生变化时会重新运行所有任务,即使某些任务并未使用已变化的值。
|
||
|
||
**错误(修改 `sortOrder` 会重新计算过滤):**
|
||
|
||
```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])
|
||
```
|
||
|
||
**正确(仅当 products 或 category 变化时才重新计算过滤):**
|
||
|
||
```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]
|
||
)
|
||
```
|
||
|
||
此模式同样适用于组合了不相关副作用的 `useEffect`:
|
||
|
||
**错误(任一依赖变化时两个副作用都会执行):**
|
||
|
||
```tsx
|
||
useEffect(() => {
|
||
analytics.trackPageView(pathname)
|
||
document.title = `${pageTitle} | My App`
|
||
}, [pathname, pageTitle])
|
||
```
|
||
|
||
**正确(副作用独立执行):**
|
||
|
||
```tsx
|
||
useEffect(() => {
|
||
analytics.trackPageView(pathname)
|
||
}, [pathname])
|
||
|
||
useEffect(() => {
|
||
document.title = `${pageTitle} | My App`
|
||
}, [pageTitle])
|
||
```
|
||
|
||
**注意:** 如果你的项目启用了 [React Compiler](https://react.dev/learn/react-compiler),它会自动优化依赖追踪,部分上述情况可能已自动处理。
|