MST

星途 面试题库

面试题:React 性能优化之 memo、useMemo 和 useCallback 的深度理解与应用

请详细说明 React 中 memo、useMemo 和 useCallback 这三个 API 在性能优化方面的原理、区别以及适用场景。假设你正在开发一个复杂的电商应用,购物车组件中包含商品列表、总价计算等功能,你会如何合理运用这三个 API 来优化该组件的性能。
15.4万 热度难度
前端开发React

知识考点

AI 面试

面试题答案

一键面试

原理

  • React.memo:用于函数组件,通过浅比较 props 来决定组件是否重新渲染。如果前后 props 浅比较结果相同,则不重新渲染组件,从而避免不必要的渲染开销。
  • useMemo:缓存一个值,只有当依赖项发生变化时才重新计算该值。它返回一个 memoized 值,在依赖项不变的情况下,始终返回相同的值,减少重复计算。
  • useCallback:缓存一个函数,只有当依赖项发生变化时才重新创建该函数。它返回一个 memoized 回调函数,常用于将回调函数传递给子组件,避免子组件因父组件重新渲染而不必要地重新渲染。

区别

  • React.memo:作用于组件级别,控制组件整体的渲染。只比较 props,对引用类型的 props 进行浅比较。
  • useMemo:用于缓存值,重点在于缓存计算结果,防止不必要的重复计算。
  • useCallback:用于缓存函数,确保在依赖项不变时函数引用不变,常用于防止子组件不必要的重新渲染。

适用场景

  • React.memo:适用于函数组件,当组件接收的 props 比较简单且不经常变化,通过浅比较 props 能有效减少渲染次数时使用。
  • useMemo:当有复杂的计算逻辑,且计算结果依赖于某些值,这些值变化不频繁时,使用 useMemo 缓存计算结果。
  • useCallback:当需要将回调函数传递给子组件,且子组件依赖于该函数引用时,使用 useCallback 确保函数引用稳定,避免子组件不必要的重新渲染。

电商应用购物车组件优化

  • 商品列表:如果商品列表组件接收的 props 主要是商品数据数组,可将商品列表组件包裹在 React.memo 中。若商品数据数组中的对象结构不深,React.memo 通过浅比较能避免不必要渲染。例如商品基本信息(名称、价格等)变化不大时,组件不会重新渲染。
  • 总价计算:使用 useMemo 来缓存总价计算结果。总价计算依赖于购物车中的商品列表,当商品列表变化时重新计算总价。示例代码如下:
import React, { useMemo } from'react';

const Cart = ({ items }) => {
    const totalPrice = useMemo(() => {
        return items.reduce((acc, item) => acc + item.price * item.quantity, 0);
    }, [items]);

    return (
        <div>
            {/* 商品列表等内容 */}
            <p>总价: {totalPrice}</p>
        </div>
    );
};

export default Cart;
  • 回调函数:如果购物车组件中有添加商品、删除商品等操作的回调函数,且这些回调函数会传递给子组件(如商品列表中的删除按钮),使用 useCallback 缓存这些回调函数。例如删除商品的回调函数:
import React, { useCallback } from'react';

const Cart = ({ items, removeItem }) => {
    const handleRemoveItem = useCallback((itemId) => {
        removeItem(itemId);
    }, [removeItem]);

    return (
        <div>
            {/* 商品列表,每个商品项的删除按钮传递 handleRemoveItem */}
        </div>
    );
};

export default Cart;

这样,在依赖项不变的情况下,回调函数引用不变,避免子组件因函数引用变化而重新渲染。