MST

星途 面试题库

面试题:React 中使用 memo 和 useMemo 优化 State 性能的区别与场景

请详细说明 React 中 memo 和 useMemo 在优化 State 性能方面的区别。在一个包含复杂计算的列表渲染组件中,如何合理运用 memo 和 useMemo 来确保 State 变化时,组件性能最优且计算不重复执行,举例说明。
48.2万 热度难度
前端开发React

知识考点

AI 面试

面试题答案

一键面试

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 变化时,组件性能最优且计算不重复执行。