Các thành phần lớp React
Trước React 16.8, các thành phần Class là cách duy nhất để theo dõi trạng thái và vòng đời của một thành phần React. Các thành phần chức năng được coi là "không có trạng thái".
Với việc bổ sung Hooks, các thành phần Function bây giờ gần như tương đương với các thành phần Class. Sự khác biệt rất nhỏ nên có thể bạn sẽ không bao giờ cần sử dụng thành phần Class trong React.
Mặc dù các thành phần Chức năng được ưu tiên hơn, nhưng hiện tại không có kế hoạch nào về việc loại bỏ các thành phần Lớp khỏi React.
Phần này sẽ cung cấp cho bạn một cái nhìn tổng quan về cách sử dụng các thành phần Class trong React.
Vui lòng bỏ qua phần này và thay vào đó sử dụng Thành phần chức năng.
Các thành phần React
Các thành phần là các bit mã độc lập và có thể tái sử dụng. Chúng phục vụ cùng mục đích như các hàm JavaScript, nhưng hoạt động riêng lẻ và trả về HTML thông qua một hàm render ().
Thành phần có hai loại, Thành phần lớp và Thành phần chức năng, trong chương này bạn sẽ tìm hiểu về Thành phần lớp.
Tạo một thành phần lớp
Khi tạo một thành phần React, tên của thành phần đó phải bắt đầu bằng một chữ cái viết hoa.
Thành phần phải bao gồm extends React.Component
câu lệnh, câu lệnh này tạo ra sự kế thừa cho React.Component và cấp cho thành phần của bạn quyền truy cập vào các chức năng của React.Component.
Thành phần cũng yêu cầu một render()
phương thức, phương thức này trả về HTML.
Thí dụ
Tạo một thành phần Lớp được gọi làCar
class Car extends React.Component {
render() {
return <h2>Hi, I am a Car!</h2>;
}
}
Bây giờ ứng dụng React của bạn có một thành phần gọi là Car, nó trả về một
<h2>
phần tử.
Để sử dụng thành phần này trong ứng dụng của bạn, hãy sử dụng cú pháp tương tự như HTML thông thường:
<Car />
Thí dụ
Hiển thị Car
thành phần trong phần tử "gốc":
ReactDOM.render(<Car />, document.getElementById('root'));
Được chứng nhận!
$ 95 GHI DANH
Cấu tạo thành phần
Nếu có một
hàm trong thành phần của bạn, thì hàm này sẽ được gọi khi thành phần được khởi tạo.constructor()
Hàm khởi tạo là nơi bạn khởi tạo các thuộc tính của thành phần.
Trong React, các thuộc tính thành phần nên được giữ trong một đối tượng được gọi
state
.
Bạn sẽ tìm hiểu thêm về phần state
sau của hướng dẫn này.
Hàm khởi tạo cũng là nơi bạn tôn trọng sự kế thừa của thành phần mẹ bằng cách bao gồm super()
câu lệnh, câu lệnh này thực thi hàm tạo của thành phần mẹ và thành phần của bạn có quyền truy cập vào tất cả các chức năng của thành phần mẹ ( React.Component
).
Thí dụ
Tạo một hàm khởi tạo trong thành phần Xe và thêm thuộc tính màu:
class Car extends React.Component {
constructor() {
super();
this.state = {color: "red"};
}
render() {
return <h2>I am a Car!</h2>;
}
}
Sử dụng thuộc tính màu trong hàm render ():
Thí dụ
class Car extends React.Component {
constructor() {
super();
this.state = {color: "red"};
}
render() {
return <h2>I am a {this.state.color} Car!</h2>;
}
}
Đạo cụ
Một cách khác để xử lý các thuộc tính thành phần là sử dụng props
.
Đạo cụ giống như các đối số của hàm và bạn gửi chúng vào thành phần dưới dạng thuộc tính.
Bạn sẽ tìm hiểu thêm về props
trong chương tiếp theo.
Thí dụ
Sử dụng một thuộc tính để chuyển một màu cho thành phần Xe và sử dụng nó trong hàm render ():
class Car extends React.Component {
render() {
return <h2>I am a {this.props.color} Car!</h2>;
}
}
ReactDOM.render(<Car color="red"/>, document.getElementById('root'));
Đạo cụ trong Trình tạo
Nếu thành phần của bạn có một hàm khởi tạo, thì các đạo cụ phải luôn được chuyển cho hàm tạo và cả React.Component thông qua super()
phương thức.
Thí dụ
class Car extends React.Component {
constructor(props) {
super(props);
}
render() {
return <h2>I am a {this.props.model}!</h2>;
}
}
ReactDOM.render(<Car model="Mustang"/>, document.getElementById('root'));
Các thành phần trong các thành phần
Chúng ta có thể tham khảo các thành phần bên trong các thành phần khác:
Thí dụ
Sử dụng thành phần Xe bên trong thành phần Nhà để xe:
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>
);
}
}
ReactDOM.render(<Garage />, document.getElementById('root'));
Các thành phần trong tệp
React là tất cả về việc sử dụng lại mã và có thể thông minh nếu chèn một số thành phần của bạn trong các tệp riêng biệt.
Để làm điều đó, hãy tạo một tệp mới có .js
phần mở rộng tệp và đặt mã bên trong nó:
Lưu ý rằng tệp phải bắt đầu bằng cách nhập React (như trước đây) và nó phải kết thúc bằng câu lệnh export default Car;
.
Thí dụ
Đây là tệp mới, chúng tôi đặt tên cho nó Car.js
:
import React from 'react';
class Car extends React.Component {
render() {
return <h2>Hi, I am a Car!</h2>;
}
}
export default Car;
Để có thể sử dụng Car
thành phần, bạn phải nhập tệp trong ứng dụng của mình.
Thí dụ
Bây giờ chúng tôi nhập Car.js
tệp trong ứng dụng và chúng tôi có thể sử dụng
Car
thành phần như thể nó được tạo ở đây.
import React from 'react';
import ReactDOM from 'react-dom';
import Car from './Car.js';
ReactDOM.render(<Car />, document.getElementById('root'));
Trạng thái thành phần lớp phản ứng
Các thành phần của React Class có một state
đối tượng tích hợp sẵn.
Bạn có thể nhận thấy rằng chúng tôi đã sử dụng state
trước đó trong phần hàm tạo thành phần.
Đối state
tượng là nơi bạn lưu trữ các giá trị thuộc tính thuộc về thành phần.
Khi state
đối tượng thay đổi, thành phần sẽ hiển thị lại.
Tạo đối tượng trạng thái
Đối tượng trạng thái được khởi tạo trong hàm tạo:
Thí dụ
Chỉ định state
đối tượng trong phương thức khởi tạo:
class Car extends React.Component {
constructor(props) {
super(props);
this.state = {brand: "Ford"};
}
render() {
return (
<div>
<h1>My Car</h1>
</div>
);
}
}
Đối tượng trạng thái có thể chứa bao nhiêu thuộc tính tùy thích:
Thí dụ
Chỉ định tất cả các thuộc tính mà thành phần của bạn cần:
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>
);
}
}
Sử dụng state
đối tượng
Tham chiếu đến state
đối tượng ở bất kỳ đâu trong thành phần bằng cách sử dụng
cú pháp:this.state.propertyname
Thí dụ:
Tham chiếu đến state
đối tượng trong
render()
phương thức:
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>
);
}
}
Thay đổi state
đối tượng
Để thay đổi một giá trị trong đối tượng trạng thái, hãy sử dụng this.setState()
phương thức.
Khi một giá trị trong state
đối tượng thay đổi, thành phần sẽ hiển thị lại, có nghĩa là đầu ra sẽ thay đổi theo (các) giá trị mới.
Thí dụ:
Thêm một nút với một onClick
sự kiện sẽ thay đổi thuộc tính màu:
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>
);
}
}
Luôn sử dụng setState()
phương thức để thay đổi đối tượng trạng thái, nó sẽ đảm bảo rằng thành phần biết rằng nó đã được cập nhật và gọi phương thức render () (và tất cả các phương thức vòng đời khác).
Vòng đời của các thành phần
Mỗi thành phần trong React có một vòng đời mà bạn có thể theo dõi và thao tác trong ba giai đoạn chính của nó.
Ba giai đoạn là: Gắn kết , Cập nhật và Ngắt kết nối .
Gắn
Gắn kết có nghĩa là đưa các phần tử vào DOM.
React có bốn phương thức tích hợp được gọi, theo thứ tự này, khi gắn kết một thành phần:
constructor()
getDerivedStateFromProps()
render()
componentDidMount()
Phương render()
thức này là bắt buộc và sẽ luôn được gọi, các phương thức khác là tùy chọn và sẽ được gọi nếu bạn xác định chúng.
constructor
Phương constructor()
thức được gọi trước bất kỳ thứ gì khác, khi thành phần được khởi tạo và nó là nơi tự nhiên để thiết lập giá trị ban đầu state
và các giá trị ban đầu khác.
Phương constructor()
thức được gọi với các
props
đối số, và bạn phải luôn bắt đầu bằng cách gọi super(props)
trước bất kỳ thứ gì khác, điều này sẽ khởi tạo phương thức khởi tạo của cha và cho phép thành phần kế thừa các phương thức từ cha ( React.Component
) của nó.
Thí dụ:
Phương constructor
thức này được gọi bởi React mỗi khi bạn tạo một thành phần:
class Header extends React.Component {
constructor(props) {
super(props);
this.state = {favoritecolor: "red"};
}
render() {
return (
<h1>My Favorite Color is {this.state.favoritecolor}</h1>
);
}
}
ReactDOM.render(<Header />, document.getElementById('root'));
getDerivedStateFromProps
Phương getDerivedStateFromProps()
thức này được gọi ngay trước khi hiển thị (các) phần tử trong DOM.
Đây là nơi tự nhiên để thiết lập state
đối tượng dựa trên ban đầu
props
.
It takes
state
as an argument, and returns an object with changes to the
state
.
The example below starts with the favorite color being
"red", but the
getDerivedStateFromProps()
method updates the favorite color based on the
favcol
attribute:
Example:
The getDerivedStateFromProps
method is called
right before the render method:
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>
);
}
}
ReactDOM.render(<Header favcol="yellow"/>, document.getElementById('root'));
render
The render()
method is required, and is the
method that actually outputs the HTML to the DOM.
Example:
A simple component with a simple render()
method:
class Header extends React.Component {
render() {
return (
<h1>This is the content of the Header component</h1>
);
}
}
ReactDOM.render(<Header />, document.getElementById('root'));
componentDidMount
The componentDidMount()
method is called after the
component is rendered.
This is where you run statements that requires that the component is already placed in the DOM.
Example:
At first my favorite color is red, but give me a second, and it is yellow instead:
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>
);
}
}
ReactDOM.render(<Header />, document.getElementById('root'));
Updating
The next phase in the lifecycle is when a component is updated.
A component is updated whenever there is a change in the component's
state
or props
.
React has five built-in methods that gets called, in this order, when a component is updated:
getDerivedStateFromProps()
shouldComponentUpdate()
render()
getSnapshotBeforeUpdate()
componentDidUpdate()
The render()
method is required and will
always be called, the others are optional and will be called if you define them.
getDerivedStateFromProps
Also at updates the getDerivedStateFromProps
method is
called. This is the first method that is called when a component gets updated.
This is still the natural place to set the state
object based on the initial props.
The example below has a button that changes the favorite color to blue, but
since the getDerivedStateFromProps()
method is called,
which updates the state with the color from the favcol attribute, the favorite color is
still
rendered as yellow:
Example:
If the component gets updated, the getDerivedStateFromProps()
method is called:
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>
);
}
}
ReactDOM.render(<Header favcol="yellow"/>, document.getElementById('root'));
shouldComponentUpdate
In the shouldComponentUpdate()
method
you can return a Boolean value that specifies whether React should continue with the rendering or not.
The default value is true
.
The example below shows what happens when the
shouldComponentUpdate()
method returns false
:
Example:
Stop the component from rendering at any update:
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>
);
}
}
ReactDOM.render(<Header />, document.getElementById('root'));
Example:
Same example as above, but this time the shouldComponentUpdate()
method returns
true
instead:
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>
);
}
}
ReactDOM.render(<Header />, document.getElementById('root'));
render
The render()
method is of course called when a component gets updated,
it has to re-render the HTML to the DOM, with the new changes.
The example below has a button that changes the favorite color to blue:
Example:
Click the button to make a change in the component's state:
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>
);
}
}
ReactDOM.render(<Header />, document.getElementById('root'));
getSnapshotBeforeUpdate
In the getSnapshotBeforeUpdate()
method
you have access to the props
and
state
before the update, meaning that
even after the update, you can check what the values were before the
update.
If the getSnapshotBeforeUpdate()
method
is present, you should also include the
componentDidUpdate()
method, otherwise you will get an error.
The example below might seem complicated, but all it does is this:
When the component is mounting it is rendered with the favorite color "red".
When the component has been mounted, a timer changes the state, and after one second, the favorite color becomes "yellow".
This action triggers the update phase, and since this component has a
getSnapshotBeforeUpdate()
method, this method is executed, and writes a
message to the empty DIV1 element.
Then the componentDidUpdate()
method is
executed and writes a message in the empty DIV2 element:
Example:
Use the
getSnapshotBeforeUpdate()
method to find out
what the state
object looked like before
the update:
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>
);
}
}
ReactDOM.render(<Header />, document.getElementById('root'));
componentDidUpdate
The componentDidUpdate
method
is called after the component is updated in the DOM.
The example below might seem complicated, but all it does is this:
When the component is mounting it is rendered with the favorite color "red".
When the component has been mounted, a timer changes the state, and the color becomes "yellow".
This action triggers the update phase, and since this component has
a componentDidUpdate
method, this method is
executed and writes a message in the empty DIV element:
Example:
The componentDidUpdate
method is called
after the update has been rendered in the 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>
);
}
}
ReactDOM.render(<Header />, document.getElementById('root'));
Unmounting
The next phase in the lifecycle is when a component is removed from the DOM, or unmounting as React likes to call it.
React has only one built-in method that gets called when a component is unmounted:
componentWillUnmount()
componentWillUnmount
The componentWillUnmount
method is
called when the component is about to be removed from the DOM.
Example:
Click the button to delete the header:
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>
);
}
}
ReactDOM.render(<Container />, document.getElementById('root'));