You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ReactJS中如何避免子组件重复渲染?

父组件状态变化时避免子组件重复渲染的解决方案

下面是几种实用的解决方案,附代码示例,帮你快速理解:

1. React.memo() 配合浅比较

React.memo是一个高阶组件,它会对组件的props进行浅比较:如果前后props没有变化,就跳过子组件的重新渲染。

代码示例

子组件(用React.memo包裹)

import React from 'react';

const ChildComponent = React.memo(({ name }) => {
  console.log('子组件渲染了');
  return <div>Hello, {name}</div>;
});

export default ChildComponent;

父组件

import React, { useState } from 'react';
import ChildComponent from './ChildComponent';

const ParentComponent = () => {
  const [count, setCount] = useState(0);
  const [userName] = useState('Alice');

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>点击计数:{count}</button>
      <ChildComponent name={userName} />
    </div>
  );
};

export default ParentComponent;

点击按钮改变count时,子组件的name props没有变化,所以子组件不会重新渲染,控制台不会打印"子组件渲染了"。

2. 自定义比较函数(处理复杂props)

当props是对象、数组这类引用类型时,浅比较会因为引用变化判断为props更新,这时候可以给React.memo传入第二个参数,自定义比较逻辑。

代码示例

子组件

import React from 'react';

const ChildComponent = React.memo(({ user }) => {
  console.log('子组件渲染了');
  return <div>用户姓名:{user.name},年龄:{user.age}</div>;
}, (prevProps, nextProps) => {
  // 自定义比较:只判断user的内容是否一致
  return prevProps.user.name === nextProps.user.name && prevProps.user.age === nextProps.user.age;
});

export default ChildComponent;

父组件

import React, { useState } from 'react';
import ChildComponent from './ChildComponent';

const ParentComponent = () => {
  const [count, setCount] = useState(0);

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>点击计数:{count}</button>
      {/* 每次渲染创建新对象,但自定义比较会判断内容相同 */}
      <ChildComponent user={{ name: 'Bob', age: 25 }} />
    </div>
  );
};

export default ParentComponent;

即使父组件每次渲染都传入新的user对象,只要内容和之前一致,子组件就不会重新渲染。

3. useCallback() 缓存函数props

如果父组件传给子组件的是函数,父组件每次渲染都会创建新的函数实例,导致React.memo失效。用useCallback可以缓存函数的引用,保持props不变。

代码示例

子组件

import React from 'react';

const ChildComponent = React.memo(({ onButtonClick }) => {
  console.log('子组件渲染了');
  return <button onClick={onButtonClick}>子组件按钮</button>;
});

export default ChildComponent;

父组件

import React, { useState, useCallback } from 'react';
import ChildComponent from './ChildComponent';

const ParentComponent = () => {
  const [count, setCount] = useState(0);

  // 用useCallback缓存函数,依赖项为空时,函数引用始终不变
  const handleChildClick = useCallback(() => {
    console.log('子组件按钮被点击');
  }, []);

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>点击计数:{count}</button>
      <ChildComponent onButtonClick={handleChildClick} />
    </div>
  );
};

export default ParentComponent;

handleChildClick的引用在父组件渲染时保持不变,所以子组件的props没有变化,不会重新渲染。

4. useMemo() 缓存复杂计算的props

如果传给子组件的是经过计算的数组、对象等复杂值,父组件每次渲染都会重新计算这些值,导致props引用变化。用useMemo可以缓存计算结果,保持引用不变。

代码示例

子组件

import React from 'react';

const ChildComponent = React.memo(({ filteredList }) => {
  console.log('子组件渲染了');
  return (
    <ul>
      {filteredList.map(item => <li key={item.id}>{item.name}</li>)}
    </ul>
  );
});

export default ChildComponent;

父组件

import React, { useState, useMemo } from 'react';
import ChildComponent from './ChildComponent';

const ParentComponent = () => {
  const [count, setCount] = useState(0);
  const [list] = useState([
    { id: 1, name: '苹果', isActive: true },
    { id: 2, name: '香蕉', isActive: false },
    { id: 3, name: '橙子', isActive: true }
  ]);

  // 用useMemo缓存过滤后的数组,只有list变化时才重新计算
  const filteredList = useMemo(() => {
    return list.filter(item => item.isActive);
  }, [list]);

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>点击计数:{count}</button>
      <ChildComponent filteredList={filteredList} />
    </div>
  );
};

export default ParentComponent;

父组件改变count时,filteredList的引用不变,子组件不会重新渲染。

5. 拆分组件,下沉状态

把父组件中不影响子组件的状态,拆分到独立的子组件中,让子组件的直接父组件只包含和它相关的状态,这样状态变化就不会触发子组件的重渲染。

代码示例

import React, { useState } from 'react';
import ChildComponent from './ChildComponent';

// 拆分出只管理count的组件
const CountComponent = () => {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>点击计数:{count}</button>;
};

const ParentComponent = () => {
  const [userName] = useState('Charlie');

  return (
    <div>
      <CountComponent />
      <ChildComponent name={userName} />
    </div>
  );
};

export default ParentComponent;

CountComponent的状态变化不会影响ParentComponent的渲染,因此ChildComponent也不会被重新渲染。

内容的提问来源于stack exchange,提问作者Abidur Rahman Chowdhury

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 19:47:49