面试题答案
一键面试1. React 中 memo 和 useMemo 在优化 State 性能方面的区别
- memo:
- 作用对象:主要用于函数式组件层面的优化。它会对组件的 props 进行浅比较,如果 props 没有变化,React 会复用之前渲染的结果,从而避免组件的重新渲染。
- 原理:通过浅比较前后两次 props 的值,当 props 保持不变时,阻止组件重新渲染,减少不必要的 DOM 操作和计算。这对于那些依赖 props 来决定渲染输出的组件非常有效。
- 应用场景:常用于纯展示型组件,这类组件根据传入的 props 进行渲染,且 props 变化频率较低。例如一个展示用户信息的卡片组件,只要用户信息(props)不变,就不需要重新渲染。
- useMemo:
- 作用对象:用于在函数组件内部缓存一个值,这个值通常是经过复杂计算得到的。它返回一个 memoized 值,只有当指定的依赖项发生变化时,才会重新计算这个值。
- 原理:依赖数组中的值决定了是否重新计算。当依赖数组中的任何一个值发生变化时,useMemo 会重新计算并返回新的值;如果依赖数组中的值都没有变化,就返回上一次缓存的值。
- 应用场景:适用于组件内部有复杂计算,且计算结果依赖于某些特定变量,这些变量不经常变化的场景。比如在一个图表组件中,根据大量数据计算图表的某些统计指标,只有当数据发生变化时才重新计算。
2. 在复杂计算的列表渲染组件中合理运用 memo 和 useMemo 优化性能
假设我们有一个列表渲染组件,每个列表项都需要进行复杂计算,如下示例:
import React, { useState, useMemo } from'react';
// 模拟复杂计算函数
const complexCalculation = (num) => {
// 这里进行复杂计算,例如模拟一些耗时操作
let result = 0;
for (let i = 0; i < 1000000; i++) {
result += num * Math.sin(i);
}
return result;
};
// 被 memo 包裹的列表项组件
const ListItem = React.memo(({ item }) => {
const calculatedValue = useMemo(() => complexCalculation(item.value), [item.value]);
return (
<li>
{`Item: ${item.label}, Calculated Value: ${calculatedValue}`}
</li>
);
});
const ListComponent = () => {
const [items, setItems] = useState([
{ label: 'Item1', value: 1 },
{ label: 'Item2', value: 2 },
{ label: 'Item3', value: 3 }
]);
const [otherState, setOtherState] = useState('');
// 模拟修改 otherState 触发重新渲染
const handleClick = () => {
setOtherState('new value');
};
return (
<div>
<button onClick={handleClick}>Change Other State</button>
<ul>
{items.map((item) => (
<ListItem key={item.label} item={item} />
))}
</ul>
</div>
);
};
export default ListComponent;
在上述示例中:
- ListItem 组件使用 memo:防止因为父组件(ListComponent)中与列表项无关的 state(如 otherState)变化而导致不必要的重新渲染。只有当传入 ListItem 的 item prop 发生变化时,ListItem 才会重新渲染。
- ListItem 组件内部使用 useMemo:对每个列表项的复杂计算结果进行缓存。只有当 item.value 发生变化时,才会重新执行 complexCalculation 函数进行计算,避免了在每次父组件渲染时都重复执行复杂计算,从而确保了在 State 变化时,组件性能最优且计算不重复执行。