PureComponent
PureComponent 类似于 Component,但它会跳过相同 props 和 state 的重新渲染。React 仍然支持类组件,但我们不建议在新代码中使用它们。
class Greeting extends PureComponent {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}参考
🌐 Reference
PureComponent
要跳过对相同 props 和 state 的类组件重新渲染,请继承 PureComponent 而不是 Component:
🌐 To skip re-rendering a class component for same props and state, extend PureComponent instead of Component:
import { PureComponent } from 'react';
class Greeting extends PureComponent {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}PureComponent 是 Component 的子类,并支持 所有 Component API. 扩展 PureComponent 相当于定义一个自定义的 shouldComponentUpdate 方法,该方法对 props 和 state 进行浅比较。
用法
🌐 Usage
跳过类组件不必要的重新渲染
🌐 Skipping unnecessary re-renders for class components
React 通常会在其父组件重新渲染时重新渲染一个组件。作为一种优化,你可以创建一个组件,当其父组件重新渲染时,如果其新的 props 和 state 与旧的 props 和 state 相同,React 就不会重新渲染它。类组件 可以通过继承 PureComponent 来选择此行为:
🌐 React normally re-renders a component whenever its parent re-renders. As an optimization, you can create a component that React will not re-render when its parent re-renders so long as its new props and state are the same as the old props and state. Class components can opt into this behavior by extending PureComponent:
class Greeting extends PureComponent {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}一个 React 组件应该始终具有纯渲染逻辑。这意味着如果其 props、state 和 context 没有改变,它必须返回相同的输出。通过使用 PureComponent,你是在告诉 React 你的组件符合这一要求,所以只要其 props 和 state 没有改变,React 就不需要重新渲染。然而,如果它使用的 context 发生变化,你的组件仍然会重新渲染。
🌐 A React component should always have pure rendering logic. This means that it must return the same output if its props, state, and context haven’t changed. By using PureComponent, you are telling React that your component complies with this requirement, so React doesn’t need to re-render as long as its props and state haven’t changed. However, your component will still re-render if a context that it’s using changes.
在这个例子中,请注意,当 name 发生变化时,Greeting 组件会重新渲染(因为它是其中一个属性),但当 address 发生变化时不会重新渲染(因为它没有作为属性传递给 Greeting):
🌐 In this example, notice that the Greeting component re-renders whenever name is changed (because that’s one of its props), but not when address is changed (because it’s not passed to Greeting as a prop):
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} /> </> ); }
备选方案
🌐 Alternatives
从 PureComponent 类组件迁移到函数
🌐 Migrating from a PureComponent class component to a function
我们建议在新代码中使用函数组件,而不是class组件。如果你有一些使用 PureComponent 的现有类组件,这里是你可以如何转换它们的方法。以下是原始代码:
🌐 We recommend using function components instead of class components in new code. If you have some existing class components using PureComponent, here is how you can convert them. This is the original code:
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:
🌐 When you convert this component from a class to a function, wrap it in 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} /> </> ); }