陷阱

我们建议将组件定义为函数而不是类。 查看如何迁移。

PureComponent 类似于 Component,但它会在 props 和 state 相同时跳过重新渲染。React 仍然支持类组件,但我们不建议在新代码中使用它们。

class Greeting extends PureComponent {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}

参考

PureComponent

要跳过在 props 和 state 相同时对类组件的重新渲染,请扩展 PureComponent 而不是 Component:

import { PureComponent } from 'react';

class Greeting extends PureComponent {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}

PureComponentComponent 的子类,并支持 所有 Component API。 扩展 PureComponent 等效于定义一个自定义的 shouldComponentUpdate 方法,该方法浅比较 props 和 state。

请参阅下面的更多示例。


用法

跳过类组件的不必要的重新渲染

React 通常会在组件的父组件重新渲染时重新渲染该组件。作为一种优化,你可以创建一个组件,只要它的新 props 和 state 与旧的 props 和 state 相同,React 就不会在它的父组件重新渲染时重新渲染它。 类组件 可以通过扩展 PureComponent 来选择此行为

class Greeting extends PureComponent {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}

一个 React 组件应该始终具有纯渲染逻辑。这意味着如果它的 props、state 和 context 没有改变,它必须返回相同的输出。通过使用 PureComponent,您是在告诉 React 您的组件符合此要求,因此只要它的 props 和 state 没有改变,React 就不需要重新渲染。但是,如果它正在使用的 context 发生更改,您的组件仍然会重新渲染。

在此示例中,请注意,每当更改 name 时(因为它是其 props 之一),Greeting 组件都会重新渲染,但更改 address 时不会重新渲染(因为它没有作为 prop 传递给 Greeting)。

import { PureComponent, useState } from 'react';

class Greeting extends PureComponent {
  render() {
    console.log("Greeting was rendered at", new Date().toLocaleTimeString());
    return <h3>Hello{this.props.name && ', '}{this.props.name}!</h3>;
  }
}

export default function MyApp() {
  const [name, setName] = useState('');
  const [address, setAddress] = useState('');
  return (
    <>
      <label>
        Name{': '}
        <input value={name} onChange={e => setName(e.target.value)} />
      </label>
      <label>
        Address{': '}
        <input value={address} onChange={e => setAddress(e.target.value)} />
      </label>
      <Greeting name={name} />
    </>
  );
}

陷阱

我们建议将组件定义为函数而不是类。 查看如何迁移。


备选方案

PureComponent 类组件迁移到函数

我们建议在新代码中使用函数组件而不是 类组件。如果您有一些现有的使用 PureComponent 的类组件,以下是您可以转换它们的方法。这是原始代码。

import { PureComponent, useState } from 'react';

class Greeting extends PureComponent {
  render() {
    console.log("Greeting was rendered at", new Date().toLocaleTimeString());
    return <h3>Hello{this.props.name && ', '}{this.props.name}!</h3>;
  }
}

export default function MyApp() {
  const [name, setName] = useState('');
  const [address, setAddress] = useState('');
  return (
    <>
      <label>
        Name{': '}
        <input value={name} onChange={e => setName(e.target.value)} />
      </label>
      <label>
        Address{': '}
        <input value={address} onChange={e => setAddress(e.target.value)} />
      </label>
      <Greeting name={name} />
    </>
  );
}

当您将此组件从类 转换为函数时,请将其包装在 memo 中:

import { memo, useState } from 'react';

const Greeting = memo(function Greeting({ name }) {
  console.log("Greeting was rendered at", new Date().toLocaleTimeString());
  return <h3>Hello{name && ', '}{name}!</h3>;
});

export default function MyApp() {
  const [name, setName] = useState('');
  const [address, setAddress] = useState('');
  return (
    <>
      <label>
        Name{': '}
        <input value={name} onChange={e => setName(e.target.value)} />
      </label>
      <label>
        Address{': '}
        <input value={address} onChange={e => setAddress(e.target.value)} />
      </label>
      <Greeting name={name} />
    </>
  );
}

注意

PureComponent 不同,memo 不会比较新旧 state。在函数组件中,使用相同的 state 调用 set 函数 默认情况下已经可以防止重新渲染,即使没有 memo