React 類元件
在 React 16.8 之前,類元件是跟蹤 React 元件狀態和生命週期的唯一方法。函式元件被認為是“無狀態”的。
隨著 Hooks 的新增,函式元件現在幾乎等同於類元件。它們之間的差異非常小,您可能永遠不需要在 React 中使用類元件。
儘管推薦使用函式元件,但目前沒有計劃從 React 中移除類元件。
本節將概述如何在 React 中使用類元件。
您可以跳過本節,而是使用函式元件。
React 元件
元件是獨立且可重用的程式碼片段。它們的作用與 JavaScript 函式相同,但它們獨立工作,並透過 render() 函式返回 HTML。
元件有兩種型別:類元件和函式元件,在本章中您將學習類元件。
建立類元件
建立 React 元件時,元件名稱必須以大寫字母開頭。
元件必須包含 extends React.Component 語句,該語句建立了對 React.Component 的繼承,並使您的元件可以訪問 React.Component 的函式。
元件還需要一個 render() 方法,該方法返回 HTML。
示例
建立一個名為 Car 的類元件
class Car extends React.Component {
render() {
return <h2>Hi, I am a Car!</h2>;
}
}
現在您的 React 應用程式擁有一個名為 Car 的元件,它返回一個 <h2> 元素。
要在您的應用程式中使用此元件,請使用類似於常規 HTML 的語法:<Car />
示例
在“root”元素中顯示 Car 元件
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Car />);
元件建構函式
如果您的元件中有一個 函式,則在元件初始化時將呼叫此函式。constructor()
建構函式是您初始化元件屬性的地方。
在 React 中,元件屬性應保留在名為 state 的物件中。
您將在本教程後面瞭解有關 state 的更多資訊。
建構函式也是透過包含 super() 語句來尊重父元件繼承的地方,該語句執行父元件的建構函式,並且您的元件可以訪問父元件(React.Component)的所有函式。
示例
在 Car 元件中建立一個建構函式,並新增一個 color 屬性
class Car extends React.Component {
constructor() {
super();
this.state = {color: "red"};
}
render() {
return <h2>I am a Car!</h2>;
}
}
在 render() 函式中使用 color 屬性
示例
class Car extends React.Component {
constructor() {
super();
this.state = {color: "red"};
}
render() {
return <h2>I am a {this.state.color} Car!</h2>;
}
}
Props
處理元件屬性的另一種方法是使用 props。
Props 就像函式引數一樣,您將它們作為屬性發送到元件中。
您將在下一章中瞭解有關 props 的更多資訊。
示例
使用屬性將顏色傳遞給 Car 元件,並在 render() 函式中使用它
class Car extends React.Component {
render() {
return <h2>I am a {this.props.color} Car!</h2>;
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Car color="red"/>);
建構函式中的 Props
如果您的元件具有建構函式,則 props 應始終傳遞給建構函式,並也透過 super() 方法傳遞給 React.Component。
示例
class Car extends React.Component {
constructor(props) {
super(props);
}
render() {
return <h2>I am a {this.props.model}!</h2>;
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Car model="Mustang"/>);
元件中的元件
我們可以在其他元件中引用元件
示例
在 Garage 元件中使用 Car 元件
class Car extends React.Component {
render() {
return <h2>I am a Car!</h2>;
}
}
class Garage extends React.Component {
render() {
return (
<div>
<h1>Who lives in my Garage?</h1>
<Car />
</div>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Garage />);
檔案中的元件
React 專注於程式碼重用,將一些元件放在單獨的檔案中可能很明智。
為此,請建立一個帶有 .js 副檔名的新檔案,並將程式碼放入其中
請注意,檔案必須首先匯入 React(如前所述),並且必須以 export default Car; 語句結束。
示例
這是新檔案,我們將其命名為 Car.js
import React from 'react';
class Car extends React.Component {
render() {
return <h2>Hi, I am a Car!</h2>;
}
}
export default Car;
要能夠使用 Car 元件,您必須在應用程式中匯入該檔案。
示例
現在我們將在應用程式中匯入 Car.js 檔案,並且可以使用 Car 元件,就像它在這裡建立的一樣。
import React from 'react';
import ReactDOM from 'react-dom/client';
import Car from './Car.js';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Car />);
React 類元件狀態
React 類元件具有一個內建的 state 物件。
您可能已經注意到,我們在元件建構函式部分較早地使用了 state。
state 物件是您儲存屬於元件的屬性值的地方。
當 state 物件更改時,元件將重新渲染。
建立 state 物件
state 物件在建構函式中初始化
示例
在建構函式方法中指定 state 物件
class Car extends React.Component {
constructor(props) {
super(props);
this.state = {brand: "Ford"};
}
render() {
return (
<div>
<h1>My Car</h1>
</div>
);
}
}
state 物件可以包含任意數量的屬性
示例
指定元件所需的所有屬性
class Car extends React.Component {
constructor(props) {
super(props);
this.state = {
brand: "Ford",
model: "Mustang",
color: "red",
year: 1964
};
}
render() {
return (
<div>
<h1>My Car</h1>
</div>
);
}
}
使用 state 物件
在元件中的任何位置,使用 this.state.propertyname 語法引用 state 物件
示例
在 render() 方法中引用 state 物件
class Car extends React.Component {
constructor(props) {
super(props);
this.state = {
brand: "Ford",
model: "Mustang",
color: "red",
year: 1964
};
}
render() {
return (
<div>
<h1>My {this.state.brand}</h1>
<p>
It is a {this.state.color}
{this.state.model}
from {this.state.year}.
</p>
</div>
);
}
}
更改 state 物件
要更改 state 物件中的值,請使用 this.setState() 方法。
當 state 物件中的值更改時,元件將重新渲染,這意味著輸出將根據新值進行更改。
示例
新增一個帶有 onClick 事件的按鈕,該按鈕將更改顏色屬性
class Car extends React.Component {
constructor(props) {
super(props);
this.state = {
brand: "Ford",
model: "Mustang",
color: "red",
year: 1964
};
}
changeColor = () => {
this.setState({color: "blue"});
}
render() {
return (
<div>
<h1>My {this.state.brand}</h1>
<p>
It is a {this.state.color}
{this.state.model}
from {this.state.year}.
</p>
<button
type="button"
onClick={this.changeColor}
>Change color</button>
</div>
);
}
}
始終使用 setState() 方法更改 state 物件,它將確保元件知道已更新,並呼叫 render() 方法(以及所有其他生命週期方法)。
元件的生命週期
React 中的每個元件都有一個生命週期,您可以在其三個主要階段中監控和操作它。
三個階段是:掛載、更新和解除安裝。
掛載
掛載意味著將元素放入 DOM。
React 有四個內建方法,在掛載元件時按此順序呼叫
constructor()getDerivedStateFromProps()render()componentDidMount()
render() 方法是必需的,並且始終會被呼叫,其他方法是可選的,如果您定義了它們,它們將被呼叫。
constructor
在元件初始化時,constructor() 方法會被呼叫,這是設定初始 state 和其他初始值的自然位置。
constructor() 方法以 props 作為引數被呼叫,並且您應該始終在其他任何操作之前呼叫 super(props),這將初始化父級的建構函式方法,並允許元件從其父級(React.Component)繼承方法。
示例
每次您建立元件時,React 都會呼叫 constructor 方法
class Header extends React.Component {
constructor(props) {
super(props);
this.state = {favoritecolor: "red"};
}
render() {
return (
<h1>My Favorite Color is {this.state.favoritecolor}</h1>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Header />);
getDerivedStateFromProps
getDerivedStateFromProps() 方法在渲染 DOM 中的元素之前被呼叫。
這是基於初始 props 設定 state 物件的自然位置。
它將 state 作為引數,並返回一個包含對 state 更改的物件。
下面的示例以最喜歡的顏色為“red”開始,但 getDerivedStateFromProps() 方法會根據 favcol 屬性更新喜歡的顏色
示例
getDerivedStateFromProps 方法在 render 方法之前被呼叫
class Header extends React.Component {
constructor(props) {
super(props);
this.state = {favoritecolor: "red"};
}
static getDerivedStateFromProps(props, state) {
return {favoritecolor: props.favcol };
}
render() {
return (
<h1>My Favorite Color is {this.state.favoritecolor}</h1>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Header favcol="yellow"/>);
render
render() 方法是必需的,並且是實際將 HTML 輸出到 DOM 的方法。
示例
一個具有簡單 render() 方法的簡單元件
class Header extends React.Component {
render() {
return (
<h1>This is the content of the Header component</h1>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Header />);
componentDidMount
componentDidMount() 方法在元件渲染後被呼叫。
這是您執行需要元件已放置在 DOM 中的語句的地方。
示例
起初我最喜歡的顏色是紅色,但給我一秒鐘,它變成了黃色
class Header extends React.Component {
constructor(props) {
super(props);
this.state = {favoritecolor: "red"};
}
componentDidMount() {
setTimeout(() => {
this.setState({favoritecolor: "yellow"})
}, 1000)
}
render() {
return (
<h1>My Favorite Color is {this.state.favoritecolor}</h1>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Header />);
更新
生命週期的下一個階段是元件被更新時。
每當元件的 state 或 props 發生變化時,元件就會被更新。
React 有五個內建方法,在元件更新時按此順序呼叫
getDerivedStateFromProps()shouldComponentUpdate()render()getSnapshotBeforeUpdate()componentDidUpdate()
render() 方法是必需的,並且始終會被呼叫,其他方法是可選的,如果您定義了它們,它們將被呼叫。
getDerivedStateFromProps
在更新時,getDerivedStateFromProps 方法也會被呼叫。這是元件更新時呼叫的第一個方法。
這仍然是根據初始 props 設定 state 物件的自然位置。
下面的示例有一個按鈕,它將喜歡的顏色更改為藍色,但由於呼叫了 getDerivedStateFromProps() 方法,該方法使用 favcol 屬性的顏色更新 state,因此喜歡的顏色仍然呈現為黃色
示例
如果元件被更新,getDerivedStateFromProps() 方法將被呼叫
class Header extends React.Component {
constructor(props) {
super(props);
this.state = {favoritecolor: "red"};
}
static getDerivedStateFromProps(props, state) {
return {favoritecolor: props.favcol };
}
changeColor = () => {
this.setState({favoritecolor: "blue"});
}
render() {
return (
<div>
<h1>My Favorite Color is {this.state.favoritecolor}</h1>
<button type="button" onClick={this.changeColor}>Change color</button>
</div>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Header favcol="yellow" />);
shouldComponentUpdate
在 shouldComponentUpdate() 方法中,您可以返回一個布林值,指定 React 是否應繼續渲染。
預設值為 true。
下面的示例顯示了當 shouldComponentUpdate() 方法返回 false 時會發生什麼
示例
在任何更新時停止元件渲染
class Header extends React.Component {
constructor(props) {
super(props);
this.state = {favoritecolor: "red"};
}
shouldComponentUpdate() {
return false;
}
changeColor = () => {
this.setState({favoritecolor: "blue"});
}
render() {
return (
<div>
<h1>My Favorite Color is {this.state.favoritecolor}</h1>
<button type="button" onClick={this.changeColor}>Change color</button>
</div>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Header />);
示例
與上面的示例相同,但這次 shouldComponentUpdate() 方法返回 true
class Header extends React.Component {
constructor(props) {
super(props);
this.state = {favoritecolor: "red"};
}
shouldComponentUpdate() {
return true;
}
changeColor = () => {
this.setState({favoritecolor: "blue"});
}
render() {
return (
<div>
<h1>My Favorite Color is {this.state.favoritecolor}</h1>
<button type="button" onClick={this.changeColor}>Change color</button>
</div>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Header />);
render
當元件更新時,當然會呼叫 render() 方法,它必須將 HTML 重新渲染到 DOM 中,並帶有新的更改。
下面的示例有一個按鈕,用於更改喜歡的顏色為藍色
示例
點選按鈕以更改元件的狀態
class Header extends React.Component {
constructor(props) {
super(props);
this.state = {favoritecolor: "red"};
}
changeColor = () => {
this.setState({favoritecolor: "blue"});
}
render() {
return (
<div>
<h1>My Favorite Color is {this.state.favoritecolor}</h1>
<button type="button" onClick={this.changeColor}>Change color</button>
</div>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Header />);
getSnapshotBeforeUpdate
在 getSnapshotBeforeUpdate() 方法中,您可以訪問更新之前的 props 和 state,這意味著即使在更新之後,您也可以檢查更新之前的值。
如果存在 getSnapshotBeforeUpdate() 方法,您還應該包含 componentDidUpdate() 方法,否則您將收到錯誤。
下面的示例可能看起來很複雜,但它所做的只是
當元件掛載時,它以喜歡的顏色“red”渲染。
當元件掛載完成後,一個計時器會更改狀態,一秒鐘後,喜歡的顏色變為“yellow”。
此操作會觸發更新階段,由於此元件具有 getSnapshotBeforeUpdate() 方法,因此會執行此方法,並在空的 DIV1 元素中寫入一條訊息。
然後執行 componentDidUpdate() 方法,並在空的 DIV2 元素中寫入一條訊息
示例
使用 getSnapshotBeforeUpdate() 方法來找出更新前 state 物件的樣子
class Header extends React.Component {
constructor(props) {
super(props);
this.state = {favoritecolor: "red"};
}
componentDidMount() {
setTimeout(() => {
this.setState({favoritecolor: "yellow"})
}, 1000)
}
getSnapshotBeforeUpdate(prevProps, prevState) {
document.getElementById("div1").innerHTML =
"Before the update, the favorite was " + prevState.favoritecolor;
}
componentDidUpdate() {
document.getElementById("div2").innerHTML =
"The updated favorite is " + this.state.favoritecolor;
}
render() {
return (
<div>
<h1>My Favorite Color is {this.state.favoritecolor}</h1>
<div id="div1"></div>
<div id="div2"></div>
</div>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Header />);
componentDidUpdate
componentDidUpdate 方法在元件在 DOM 中更新後被呼叫。
下面的示例可能看起來很複雜,但它所做的只是
當元件掛載時,它以喜歡的顏色“red”渲染。
當元件掛載完成後,一個計時器會更改狀態,顏色變為“yellow”。
此操作會觸發更新階段,由於此元件具有 componentDidUpdate 方法,因此會執行此方法,並在空的 DIV 元素中寫入一條訊息
示例
componentDidUpdate 方法在更新已渲染到 DOM 後被呼叫
class Header extends React.Component {
constructor(props) {
super(props);
this.state = {favoritecolor: "red"};
}
componentDidMount() {
setTimeout(() => {
this.setState({favoritecolor: "yellow"})
}, 1000)
}
componentDidUpdate() {
document.getElementById("mydiv").innerHTML =
"The updated favorite is " + this.state.favoritecolor;
}
render() {
return (
<div>
<h1>My Favorite Color is {this.state.favoritecolor}</h1>
<div id="mydiv"></div>
</div>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Header />);
解除安裝
生命週期的下一個階段是當元件從 DOM 中移除,或者解除安裝(React 喜歡這樣稱呼它)。
React 只有一個內建方法,在元件被解除安裝時會被呼叫
componentWillUnmount()
componentWillUnmount
componentWillUnmount 方法在元件即將從 DOM 中移除時被呼叫。
示例
點選按鈕以刪除標題
class Container extends React.Component {
constructor(props) {
super(props);
this.state = {show: true};
}
delHeader = () => {
this.setState({show: false});
}
render() {
let myheader;
if (this.state.show) {
myheader = <Child />;
};
return (
<div>
{myheader}
<button type="button" onClick={this.delHeader}>Delete Header</button>
</div>
);
}
}
class Child extends React.Component {
componentWillUnmount() {
alert("The component named Header is about to be unmounted.");
}
render() {
return (
<h1>Hello World!</h1>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Container />);