Trong bài trước, chúng ta sử dụng props để truyền data từ parent component tới component. Vấn đề đặt ra là làm sao chúng ta có thể tự cập nhật được data. Lúc này chúng ta sử dụng State
State là gì?
State dùng để lưu trữ giá trị thuộc về component trong ReactJS. Nó chủ yếu được sử dụng để cập nhật component khi người dùng thực hiện một số hành động như nhấp vào nút, nhập một số văn bản, nhấn một số phím, v.v.
Tóm lại
- Là 1 object chứa component data
- Access bởi component
- Chỉ được update qua setState()
Có 2 loại components trong React: class và functional components.
Class components là ES6 class được extend từ built-in Component class, nên có state và lifecycle methods
import { Component } from 'react';
class Message extends Component {
constructor(props) {
super(props);
this.state = {
message: ''
};
}
componentDidMount() {
/* ... */
}
render() {
return <div>{this.state.message}</div>;
}
}
- Hiệu suất: setState() là một phương thức không đồng bộ, có nghĩa là nó không cập nhật trạng thái ngay lập tức. Thay vào đó, nó thêm một nhiệm vụ vào hàng đợi để cập nhật trạng thái khi React có thời gian. Điều này có thể cải thiện hiệu suất trong các trường hợp bạn cập nhật trạng thái thường xuyên.
- Độ tin cậy: setState() đảm bảo rằng trạng thái mới được đồng bộ hóa với UI. Nếu bạn gán giá trị trực tiếp cho trạng thái, điều này có thể dẫn đến trạng thái bị lệch với UI.
- Tính linh hoạt: setState() cho phép bạn cung cấp một hàm làm đối số để xử lý trạng thái mới trước khi cập nhật UI. Điều này có thể hữu ích nếu bạn cần thực hiện logic bổ sung khi trạng thái thay đổi.
Sử dụng State để cập nhật data
Giả sử bạn có 1 component là 1 clock dùng để hiển thị data Yêu cầu đặt ra là clock component cần được cập nhật thời gian theo realtime
Tạo component Clock.tsximport React, { Component } from "react";
import './clock.css';
class Clock extends React.Component {
render() {
const currentTime = new Date(),
hours = currentTime.getHours(),
minutes = currentTime.getMinutes(),
seconds = currentTime.getSeconds(),
ampm = hours >= 12 ? 'pm' : 'am';
return (
<div className="clock">
{hours == 0 ? 12 : hours > 12 ? hours - 12 : hours}:
{minutes > 9 ? minutes : `0${minutes}`}:
{seconds > 9 ? seconds : `0${seconds}`} {ampm}
</div>
);
}
}
export default Clock;
clock.css
:root {
--firstColor: rgba(0, 169, 158, 1);
--secondColor: rgba(0, 191, 150, 1);
--textColor: #fff;
}
.clock {
position: relative;
border-radius: 0.5em;
margin: 10px auto;
font-family: "Open Sans", sans-serif;
text-align: center;
font-size: 60px;
color: var(--textColor);
line-height: 2em;
background: #eee;
/* Old browsers */
background: var(--firstColor);
padding-left: 0.5em;
padding-right: 0.5em;
}
@media only screen and (min-width: 700px) and (max-width: 1000px) {
.clock {
font-size: 50px;
}
}
@media only screen and (min-width: 500px) and (max-width: 699px) {
.clock {
font-size: 45px;
}
}
@media only screen and (min-width: 200px) and (max-width: 499px) {
.clock {
font-size: 40px;
}
}
Cập nhật lại component App.tsx
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'
import Clock from './components/Clock'
function App() {
return (
<>
<div>
<a href="https://vitejs.dev" target="_blank">
<img src={viteLogo} className="logo" alt="Vite logo" />
</a>
<a href="https://react.dev" target="_blank">
<img src={reactLogo} className="logo react" alt="React logo" />
</a>
</div>
<h1>Vite + React</h1>
<div className="card">
<Clock />
</div>
<p className="read-the-docs">
Click on the Vite and React logos to learn more
</p>
</>
)
}
export default App
Ở đoạn code trên, chúng ta chỉ render đồng hồ và hiển thị thời gian tại thời điểm mà trình duyệt render. Để hiển thị đồng hồ theo thời gian thực, chúng ta sử dụng State
State là gì?
State trong React là một đối tượng được sử dụng để lưu trữ dữ liệu của một component. Khi state thay đổi, component cũng được render lại. State chỉ được sử dụng trong nội bộ một component và mỗi component sẽ có một state riêng của nó
Khởi tạo State
Để khởi tạo state object, bạn có thể dùng constructor method.
State object có thể chứa nhiều thuộc tính tùy ý và bạn có thể tham chiếu đến chúng bằng cách dùng this.state.propertyname.
Để thay đổi giá trị của state object, bạn phải dùng this.setState() method. Khi giá trị của state object thay đổi, component sẽ được render lại và output sẽ thay đổi theo giá trị mới
Lưu ý
Bạn phải dùng this.setState() để thay đổi state vì this.setState() là một phương thức bất đồng bộ, nghĩa là nó sẽ cập nhật state và render lại component sau khi hoàn thành các câu lệnh khác. Nếu bạn thay đổi state trực tiếp bằng cách gán giá trị mới cho this.state, thì React sẽ không biết được state đã thay đổi và sẽ không render lại component.
Dưới đây là 2 ví dụ về cách sử dụng setState(), trong đó ví dụ 2 sử dụng thêm action componentDidMount() để gọi hàm setTimeout, trigger tự động sau 1s
import React, { Component } from 'react';
class Counter extends Component {
constructor(props) {
super(props);
this.state = {
count: 0 // khởi tạo state object với thuộc tính count
};
}
increment = () => {
this.setState({ // dùng this.setState() để thay đổi giá trị của count
count: this.state.count + 1 // tăng giá trị của count lên 1
});
};
render() {
return (
<div>
<h1>Counter</h1>
<p>You clicked {this.state.count} times</p> // truy cập state object bằng this.state.count
<button onClick={this.increment}>Click me</button> // gọi hàm increment khi nhấn nút
</div>
);
}
}
export default Counter;
Dưới đây là 1 trường hợp khác sử dụng setState nhưng không sử dụng trigger từ button
import React, { Component } from 'react';
class App extends Component {
constructor(props){
super(props);
this.state = {
data: 'Jordan Belfort'
}
}
getData(){
setTimeout(() => {
console.log('Our data is fetched');
this.setState({
data: 'Hello WallStreet'
})
}, 1000)
}
componentDidMount(){
this.getData();
}
render() {
return(
<div>
{this.state.data}
</div>
)
}
}
export default App;
componentDidMount(): Được gọi sau khi đã hiển thị component ra ngoài trình duyệt, và hàm này được thực hiện một lần duy nhất. Hàm này được gọi để thông báo component đã tồn tại trên DOM, từ đó các thao tác trên DOM có thể thực hiện bình thường với component này.
Quay trở lại ví dụ 1, chúng ta sẽ sử dụng setState kết hợp với componentDidMount()
import React, { Component } from "react";
import "./clock.css";
import IClockModel from "../models/IClockModel";
class Clock extends React.Component {
constructor(props: any) {
super(props);
this.state = {
clock: this.getTime()
};
}
getTime(): IClockModel {
const currentTime = new Date();
var clock: IClockModel = {
hours: currentTime.getHours(),
minutes: currentTime.getMinutes(),
seconds: currentTime.getSeconds(),
ampm: currentTime.getHours() >= 12 ? "pm" : "am",
};
return clock;
}
componentDidMount() {
console.log("componentDidMount");
this.setTimer();
}
setTimer() {
clearTimeout(this.timeout);
this.timeout = setTimeout(this.updateClock.bind(this), 1000);
}
updateClock() {
this.setState({
clock: this.getTime()
}, this.setTimer);
}
render() {
const {hours, minutes, seconds, ampm} = this.state.clock;
return (
<div className="clock">
{hours == 0 ? 12 : hours > 12 ? hours - 12 : hours}:
{minutes > 9 ? minutes : `0${minutes}`}:
{seconds > 9 ? seconds : `0${seconds}`} {ampm}
</div>
);
}
}
export default Clock;
Tham khảo
React Lifecycle Methods: render and componentDidMount
Vòng đời của component trong React
Sử dụng .bind() cho các hàm của Class Components trong React liệu có cần thiết?
Hi vọng với những đoạn code nhỏ này sẽ giúp bạn hiểu thêm về State
Chúc các bạn thành công
Nhận xét
Đăng nhận xét