useMemo 是 React 中用于性能优化的核心 Hook,其主要作用是缓存计算结果,避免在每次渲染时重复执行昂贵的计算,同时确保引用的稳定性以提高组件行为的可预测性。以下是其核心知识点和最佳实践:
一、基础用法与语法
useMemo 接收两个参数:计算函数和依赖项数组。当依赖项变化时,重新执行计算函数;否则直接返回缓存值。
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
• 计算函数:包含需要缓存的逻辑(如复杂运算、数据转换)。
• 依赖项数组:决定何时重新计算。若省略,每次渲染都会重新计算;若为空数组([]),仅首次渲染计算。
二、核心应用场景
-
避免昂贵的重复计算
适用于复杂数学运算(如斐波那契数列)、数据过滤/排序、大数组处理等场景。const sum = useMemo(() => numbers.reduce((acc, val) => acc + val, 0), [numbers]); -
稳定对象/数组的引用
当将派生数据(如合并对象、生成的数组)传递给子组件或自定义 Hook 时,useMemo可避免因引用变化触发不必要的副作用或子组件重渲染。const mergedData = useMemo(() => ({ ...dataA, ...dataB }), [dataA, dataB]); -
优化子组件渲染
结合React.memo使用,缓存子组件的 props(如对象、函数),减少因父组件渲染导致的子组件无效更新。const userList = useMemo(() => users.map(user => <User key={user.id} data={user} />), [users]);
三、常见错误与避坑指南
-
依赖项缺失或错误
若依赖项未正确设置,可能导致缓存值未及时更新。例如,过滤数据时遗漏状态变量依赖:// 错误:依赖项缺失 filter 导致结果不更新 const filteredData = useMemo(() => data.filter(item => item.includes(filter)), []); -
滥用导致代码冗余
简单计算(如字符串拼接、基本算术)无需使用useMemo,过度优化会增加代码复杂度且无实质收益。 -
副作用逻辑误用
useMemo的计算函数应为纯函数,避免包含副作用(如 API 调用、DOM 操作)。副作用应使用useEffect处理。
四、最佳实践
-
先确保功能正确,再针对性优化
优先编写无useMemo的功能代码,确认存在性能瓶颈后再引入优化。 -
结合
React.memo使用
对纯展示型子组件使用React.memo,并通过useMemo缓存其 props,实现双重优化。 -
区分
useMemo与useCallback
•useMemo缓存计算结果(值、对象、数组)。•
useCallback缓存函数本身,适用于避免子组件因函数引用变化重渲染。
五、何时应避免使用?
• 计算成本极低:如简单加减法、字符串拼接。
• 数据频繁变化:依赖项频繁变动时,缓存效果有限,甚至可能增加性能开销。
示例:优化斐波那契计算
function App() {
const [n, setN] = useState(1);
const fib = useMemo(() => {
let a = 0, b = 1;
for (let i = 2; i <= n; i++) {
[a, b] = [b, a + b];
}
return b;
}, [n]); // 仅当 n 变化时重新计算
return <div>{fib}</div>;
}
此例中,useMemo 避免了每次渲染时重复执行高成本的循环计算。
通过合理使用 useMemo,开发者能在复杂场景下显著提升性能,同时保持代码的可维护性。核心原则是:优先解决正确性问题,再针对性能瓶颈精准优化。
787

被折叠的 条评论
为什么被折叠?



