React 性能优化基础:useCallback、React.memo

在复杂的应用中,不必要的渲染是导致性能问题的常见原因。

当一个组件的 stateprops 发生变化,它会重新渲染,更重要的是,当一个父组件重新渲染时,所有子组件也会重新渲染。

如果子组件是一个复杂的组件,重新渲染就会造成性能浪费。

React.memo

React.memo 会对组件的 props 进行浅比较,如果新旧 props 相同,则会复用上一次的渲染结果。

js
import { memo } from 'react';

const Child = memo(({ name }) => {
    return (
        <div>
            Hello, {name}
        </div>
    );
});

export default Child;

现在,只有当 name 发生变化时,Child 组件才会重新渲染。

useCallback

每次父组件渲染时,其中定义的函数会被重新创建。

即使函数内容完全一样,他们也是两个不同的函数。这意味着什么?

当组件重新渲染时,handleChildClick 函数会被重新创建,即使它没有发生变化,所以子组件还是会重新渲染。

useCallback 可以解决这个问题

依赖数组的重要性

useCallback 的第二个参数是依赖数组,当数组中的任何值发生变化时,函数会被重新创建。

js
// 当 id 变化时,handleFetch 会被重新创建
const handleFetch = useCallback(() => {
    fetchData(id);
}, [id]);

如果函数内部使用了某些外部变量,而这些变量没有被添加到依赖数组中,可能会导致函数使用过时的值。

React.memo 与 useCallback 结合使用

React.memouseCallback 结合使用效果最佳:

在这个例子中,即使 ParentComponent 因为 count 状态变化而重新渲染,Child 组件也不会重新渲染,因为:

  1. handleChildClick 函数被 useCallback 缓存,不会重新创建
  2. name 属性没有变化
  3. Child 组件被 memo 包裹,会对 props 进行浅比较

总结

性能优化是一个平衡的过程,过度优化可能会使代码变得复杂而难以维护。在实际开发中,应该先确认是否存在性能问题,再有针对性地进行优化。

  • 使用 React.memo 避免不必要的子组件渲染
  • 使用 useCallback 缓存函数,避免每次渲染都创建新的函数实例
  • 正确设置 useCallback 的依赖数组,确保函数使用最新的值
  • 将两者结合使用,可以有效减少不必要的渲染

记住,性能优化应该是有的放矢,而不是盲目应用。

useMemo VS useState + useEffect:避免额外渲染
C++中的指针和引用的区别

评论区

评论加载中...