React函数组件中,如何避免子组件不必要的渲染

376 阅读3分钟

以下纯为个人记录,还有有误之处,还请指点。

在React函数组件中,可以通过使用React.memo()useMemo()来避免子组件不必要的渲染。 使用React.memo()React.memo()是一个高阶组件,用于包装函数组件。它会对组件的输入进行浅层比较,如果组件的输入没有发生变化,则会跳过渲染,从而提高性能。

示例代码如下:

import React from 'react';

const ChildComponent = React.memo(({ data }) => {
  // 渲染子组件的逻辑
  return <div>{data}</div>;
});

const ParentComponent = () => {
  const data = useMemo(() => fetchData(), []);
  
  return (
    <div>
      {/* 其他组件 */}
      <ChildComponent data={data} />
    </div>
  );
};

在上述代码中,ChildComponent被包裹在React.memo()中。当ParentComponent重新渲染时,如果data没有发生变化,ChildComponent将不会重新渲染。 通过使用React.memo()useMemo(),可以优化React函数组件的性能,避免不必要的子组件渲染,并提升整体应用的性能。

补充:useCallback

useCallback()是React的一个Hook,用于优化函数的性能。它会返回一个记忆化的回调函数,该回调函数只在依赖项发生变化时才会重新创建。

使用useCallback()可以避免在每次渲染时都重新创建相同的回调函数,特别是当这些回调函数作为props传递给子组件时,可以提高子组件的性能。

下面是useCallback()的基本语法:

const memoizedCallback = useCallback(callback, dependencies);
-   `callback`:要记忆化的回调函数。
-   `dependencies`:一个依赖项数组,当其中任何一个依赖项发生变化时,会重新创建回调函数。

示例代码如下

import React, { useCallback } from 'react';

const ChildComponent = ({ onClick }) => {
  // 渲染子组件的逻辑
  return <button onClick={onClick}>Click</button>;
};

const ParentComponent = () => {
  const handleClick = useCallback(() => {
    console.log('Button clicked');
  }, []);

  return (
    <div>
      {/* 其他组件 */}
      <ChildComponent onClick={handleClick} />
    </div>
  );
};

在上述代码中,通过useCallback()包裹了handleClick回调函数。由于dependencies为空数组,所以回调函数只会在组件首次渲染时创建一次,并且在后续渲染中复用。这样做可以避免每次渲染时都创建新的回调函数。

注意:当传递给子组件的回调函数有依赖项时,需要将这些依赖项添加到useCallback()dependencies数组中,以确保在依赖项发生变化时重新创建回调函数。例如:

const ParentComponent = () => {
  const handleClick = useCallback(() => {
    console.log('Button clicked');
  }, [data]);

  return (
    <div>
      {/* 其他组件 */}
      <ChildComponent onClick={handleClick} />
    </div>
  );
};

在上述代码中,如果data发生变化,handleClick回调函数也会重新创建。

通过使用useCallback(),可以有效地优化React函数组件的性能,避免不必要的函数创建,并提升应用的整体性能。

useCallback()并不能直接避免子组件的不必要渲染

useCallback()只是用于优化回调函数的性能,它会返回一个记忆化的回调函数。当依赖项发生变化时,才会重新创建回调函数。这样可以确保在父组件重新渲染时,传递给子组件的回调函数引用保持稳定,避免不必要的子组件重新渲染。

但是,子组件是否进行重新渲染还取决于其他因素,例如子组件的props或状态的变化。即使使用了useCallback(),如果子组件的props或状态发生了变化,它仍然可能进行重新渲染。

为了避免不必要的子组件渲染,你可以考虑使用React.memo()来包裹子组件。React.memo()是一个高阶组件,用于对比前后两次渲染的props是否发生变化。如果props没有发生变化,React.memo()会阻止子组件的重新渲染。