PureComponent
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>;
}
}
PureComponent
是 Component
的子類別,並支援 所有 Component
API。 繼承 PureComponent
等同於定義一個自訂的 shouldComponentUpdate
方法,該方法會淺層比較 props 和 state。
用法
跳過類別元件不必要的重新渲染
React 通常會在父組件重新渲染時,重新渲染其所有子組件。為了優化效能,您可以建立一個組件,只要它的新 props 和 state 與舊的 props 和 state 相同,React 就不會在父組件重新渲染時重新渲染它。 類別組件 (Class components) 可以透過繼承 PureComponent
來選擇使用這種行為。
class Greeting extends PureComponent {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}
一個 React 組件應該始終具有 純粹的渲染邏輯 (pure rendering logic)。 這表示如果它的 props、state 和 context 沒有改變,它必須返回相同的輸出。透過使用 PureComponent
,您是在告訴 React 您的組件符合此要求,因此只要它的 props 和 state 沒有改變,React 就不需要重新渲染它。但是,如果它正在使用的 context 發生變化,您的組件仍然會重新渲染。
在此範例中,請注意 Greeting
組件會在 name
更改時重新渲染(因為它是其 props 之一),但在 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} /> </> ); }