--- 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),它会自动优化依赖追踪,部分上述情况可能已自动处理。