Thành phần lớp phản ứng
Trước React 16.8, các thành phần Lớp là cách duy nhất để theo dõi trạng thái và vòng đời trên 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 hiện nay 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 cái nhìn tổng quan về cách sử dụng các thành phần Lớp trong React.
Vui lòng bỏ qua phần này và thay vào đó hãy sử dụng Thành phần hàm.
Thành phần phản ứng
Các thành phần là các đoạn 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 độc lập và trả về HTML thông qua hàm render().
Các thành phần có hai loại, thành phần Lớp và thành phần Hàm, trong chương này bạn sẽ tìm hiểu về các thành phần Lớp.
Tạo một thành phần lớp
Khi tạo thành phần React, tên của thành phần đó phải bắt đầu bằng chữ in hoa.
Thành phần này phải bao gồm câu lệnh extends React.Component
, 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 này cũng yêu cầu phương thức render()
, phương thức này trả về HTML.
Ví dụ
Tạo một thành phần Lớp có tên 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 tên là Car, trả về phần tử <h2>
.
Để 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 />
Ví dụ
Hiển thị thành phần Car
trong phần tử "root":
const root = ReactDOM.createRoot(document.getElementById('root')); root.render(<Car />);
Được chứng nhận!
$95 ĐĂNG KÝ
Trình xây dựng thành phần
Nếu có hàm
trong thành phần của bạn, 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 của thành phần phải được giữ trong một đối tượng có tên là state
.
Bạn sẽ tìm hiểu thêm về state
sau trong hướng dẫn này.
Hàm khởi tạo cũng là nơi bạn tôn vinh sự kế thừa của thành phần cha mẹ bằng cách bao gồm câu lệnh super()
, câu lệnh này thực thi hàm khởi tạo của thành phần cha 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 cha mẹ ( React.Component
).
Ví dụ
Tạo hàm khởi tạo trong thành phần Xe hơi 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():
Ví 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 của 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.
Ví dụ
Sử dụng một thuộc tính để chuyển màu cho thành phần Xe hơi 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>; } } const root = ReactDOM.createRoot(document.getElementById('root')); root.render(<Car color="red"/>);
Props trong Constructor
Nếu thành phần của bạn có hàm tạo, thì các đạo cụ phải luôn được chuyển đến hàm tạo và cả React.Component thông qua phương thức super()
.
Ví dụ
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"/>);
Thành phần trong 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:
Ví dụ
Sử dụng thành phần Ô tô 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> ); } } const root = ReactDOM.createRoot(document.getElementById('root')); root.render(<Garage />);
Các thành phần trong tập tin
React chủ yếu là về việc sử dụng lại mã và việc chèn một số thành phần của bạn vào các tệp riêng biệt có thể là một điều thông minh.
Để làm điều đó, hãy tạo một tệp mới có phần mở rộng tệp .js
và đặt mã vào bên trong tệp đó:
Lưu ý rằng tệp phải bắt đầu bằng cách nhập React (như trước) và nó phải kết thúc bằng câu lệnh export default Car;
.
Ví dụ
Đây là tệp mới, chúng tôi đặt tên là 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 thành phần Car
, bạn phải nhập tệp vào ứng dụng của mình.
Ví dụ
Bây giờ chúng ta nhập tệp Car.js
vào ứng dụng và có thể sử dụng thành phần Car
như thể nó được tạo ở đây.
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 />);
Trạng thái thành phần lớp phản ứng
Các thành phần Lớp React có một đối tượng state
tích hợp.
Bạn có thể nhận thấy rằng chúng ta đã sử dụng state
trước đó trong phần hàm tạo thành phần.
Đối tượng state
là nơi bạn lưu trữ các giá trị thuộc tính thuộc về thành phần.
Khi đối tượng state
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:
Ví dụ
Chỉ định đối tượng state
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:
Ví 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 đối tượng state
Tham chiếu đến đối tượng state
ở bất kỳ đâu trong thành phần bằng cách sử dụng this.state. propertyname
cú pháp this.state. propertyname
:
Ví dụ:
Tham khảo đối tượng state
trong phương thức render()
:
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 đối tượng state
Để thay đổi giá trị trong đối tượng trạng thái, hãy sử dụng phương thức this.setState()
.
Khi một giá trị trong đối tượng state
thay đổi, thành phần sẽ kết xuất lại, nghĩa là đầu ra sẽ thay đổi theo (các) giá trị mới.
Ví dụ:
Thêm nút có sự kiện onClick
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 phương thức setState()
để thay đổi đối tượng trạng thái, nó sẽ đảm bảo rằng thành phần đó biết 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 đều có 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ự sau khi gắn một thành phần:
-
constructor()
-
getDerivedStateFromProps()
-
render()
-
componentDidMount()
Phương thức render()
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.
người xây dựng
Phương thức constructor()
được gọi trước bất kỳ thứ gì khác, khi thành phần được khởi tạo và đó là nơi tự nhiên để thiết lập state
ban đầu và các giá trị ban đầu khác.
Phương thức constructor()
được gọi với các props
làm đố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 mẹ và cho phép thành phần kế thừa các phương thức từ cha mẹ của nó ( React.Component
).
Ví dụ:
Phương thức constructor
được React gọi 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> ); } } const root = ReactDOM.createRoot(document.getElementById('root')); root.render(<Header />);
getDerivedStateFromProps
Phương thức getDerivedStateFromProps()
đượ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 đối tượng state
dựa trên props
ban đầu.
Nó lấy state
làm đối số và trả về một đối tượng có thay đổi về state
.
Ví dụ bên dưới bắt đầu với màu yêu thích là "đỏ", nhưng phương thức getDerivedStateFromProps()
cập nhật màu yêu thích dựa trên thuộc tính favcol
:
Ví dụ:
Phương thức getDerivedStateFromProps
được gọi ngay trước phương thức kết xuất:
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"/>);
kết xuất
Phương thức render()
là bắt buộc và là phương thức thực sự xuất HTML sang DOM.
Ví dụ:
Một thành phần đơn giản với phương thức render()
đơn giản:
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 />);
thành phầnDidMount
Phương thức componentDidMount()
được gọi sau khi thành phần được hiển thị.
Đây là nơi bạn chạy các câu lệnh yêu cầu thành phần đó đã được đặt trong DOM.
Ví dụ:
Lúc đầu, màu yêu thích của tôi là màu đỏ, nhưng hãy chờ một chút, thay vào đó là màu vàng:
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 />);
Đang cập nhật
Giai đoạn tiếp theo trong vòng đời là khi một thành phần được cập nhật .
Một thành phần được cập nhật bất cứ khi nào có sự thay đổi về state
hoặc props
của thành phần đó.
React có năm phương thức tích hợp được gọi theo thứ tự sau khi một thành phần được cập nhật:
-
getDerivedStateFromProps()
-
shouldComponentUpdate()
-
render()
-
getSnapshotBeforeUpdate()
-
componentDidUpdate()
Phương thức render()
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.
getDerivedStateFromProps
Cũng tại các bản cập nhật, phương thức getDerivedStateFromProps
được gọi. Đây là phương thức đầu tiên được gọi khi một thành phần được cập nhật.
Đây vẫn là nơi tự nhiên để đặt đối tượng state
dựa trên các đạo cụ ban đầu.
Ví dụ bên dưới có một nút thay đổi màu yêu thích thành màu xanh lam, nhưng vì phương thức getDerivedStateFromProps()
được gọi, phương thức này cập nhật trạng thái với màu từ thuộc tính favcol nên màu yêu thích vẫn được hiển thị là màu vàng:
Ví dụ:
Nếu thành phần được cập nhật, phương thức getDerivedStateFromProps()
sẽ được gọi:
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" />);
nênComponentUpdate
Trong phương thức shouldComponentUpdate()
, bạn có thể trả về giá trị Boolean chỉ định xem React có nên tiếp tục hiển thị hay không.
Giá trị mặc định là true
.
Ví dụ bên dưới cho thấy điều gì xảy ra khi phương thức shouldComponentUpdate()
trả về false
:
Ví dụ:
Ngăn thành phần hiển thị ở bất kỳ bản cập nhật nào:
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 />);
Ví dụ:
Ví dụ tương tự như trên, nhưng lần này phương thức shouldComponentUpdate()
trả về 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 />);
kết xuất
Tất nhiên, phương thức render()
được gọi khi một thành phần được cập nhật , nó phải kết xuất lại HTML thành DOM với những thay đổi mới.
Ví dụ bên dưới có nút thay đổi màu yêu thích thành màu xanh:
Ví dụ:
Nhấp vào nút để thực hiện thay đổi trạng thái của thành phần:
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
Trong phương thức getSnapshotBeforeUpdate()
bạn có quyền truy cập vào props
và state
trước khi cập nhật, nghĩa là ngay cả sau khi cập nhật, bạn vẫn có thể kiểm tra các giá trị trước khi cập nhật.
Nếu có phương thức getSnapshotBeforeUpdate()
, bạn cũng nên bao gồm phương thức componentDidUpdate()
, nếu không bạn sẽ gặp lỗi.
Ví dụ dưới đây có vẻ phức tạp, nhưng tất cả những gì nó làm là:
Khi thành phần đang được gắn kết, nó sẽ được hiển thị với màu yêu thích là "đỏ".
Khi thành phần đã được lắp, đồng hồ hẹn giờ sẽ thay đổi trạng thái và sau một giây, màu yêu thích sẽ trở thành "vàng".
Hành động này kích hoạt giai đoạn cập nhật và vì thành phần này có phương thức getSnapshotBeforeUpdate()
nên phương thức này được thực thi và ghi thông báo vào phần tử DIV1 trống.
Sau đó, phương thức componentDidUpdate()
được thực thi và ghi một thông báo vào phần tử DIV2 trống:
Ví dụ:
Sử dụng phương thức getSnapshotBeforeUpdate()
để tìm hiểu xem đối tượng state
trông như thế nào trước khi cập nhật:
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 />);
thành phầnDidUpdate
Phương thức componentDidUpdate
được gọi sau khi thành phần được cập nhật trong DOM.
Ví dụ dưới đây có vẻ phức tạp, nhưng tất cả những gì nó làm là:
Khi thành phần đang được gắn kết, nó sẽ được hiển thị với màu yêu thích là "đỏ".
Khi thành phần đã được gắn, bộ hẹn giờ sẽ thay đổi trạng thái và màu trở thành "vàng".
Hành động này kích hoạt giai đoạn cập nhật và vì thành phần này có phương thức componentDidUpdate
nên phương thức này được thực thi và ghi thông báo vào phần tử DIV trống:
Ví dụ:
Phương thức componentDidUpdate
được gọi sau khi bản cập nhật được hiển thị trong 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 />);
Ngắt kết nối
Giai đoạn tiếp theo trong vòng đời là khi một thành phần bị xóa khỏi DOM hoặc ngắt kết nối như React muốn gọi.
React chỉ có một phương thức tích hợp sẵn được gọi khi một thành phần chưa được kết nối:
-
componentWillUnmount()
thành phầnWillUnmount
Phương thức componentWillUnmount
được gọi khi thành phần sắp bị xóa khỏi DOM.
Ví dụ:
Bấm vào nút để xóa tiêu đề:
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 />);