Chuyển đến nội dung chính

React: State trong ReactJs - Day 6

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>;
  }
}
Có một số lý do tại sao bạn nên sử dụng setState() thay vì gán giá trị trực tiếp cho trạng thái trong React.
  • 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.tsx
import 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

Bài đăng phổ biến từ blog này

[ASP.NET MVC] Authentication và Authorize

Một trong những vấn đề bảo mật cơ bản nhất là đảm bảo những người dùng hợp lệ truy cập vào hệ thống. ASP.NET đưa ra 2 khái niệm: Authentication và Authorize Authentication xác nhận bạn là ai. Ví dụ: Bạn có thể đăng nhập vào hệ thống bằng username và password hoặc bằng ssh. Authorization xác nhận những gì bạn có thể làm. Ví dụ: Bạn được phép truy cập vào website, đăng thông tin lên diễn đàn nhưng bạn không được phép truy cập vào trang mod và admin.

ASP.NET MVC: Cơ bản về Validation

Validation (chứng thực) là một tính năng quan trọng trong ASP.NET MVC và được phát triển trong một thời gian dài. Validation vắng mặt trong phiên bản đầu tiên của asp.net mvc và thật khó để tích hợp 1 framework validation của một bên thứ 3 vì không có khả năng mở rộng. ASP.NET MVC2 đã hỗ trợ framework validation do Microsoft phát triển, tên là Data Annotations. Và trong phiên bản 3, framework validation đã hỗ trợ tốt hơn việc xác thực phía máy khách, và đây là một xu hướng của việc phát triển ứng dụng web ngày nay.

Tổng hợp một số kiến thức lập trình về Amibroker

Giới thiệu về Amibroker Amibroker theo developer Tomasz Janeczko được xây dựng dựa trên ngôn ngữ C. Vì vậy bộ code Amibroker Formula Language sử dụng có syntax khá tương đồng với C, ví dụ như câu lệnh #include để import hay cách gói các object, hàm trong các block {} và kết thúc câu lệnh bằng dấu “;”. AFL trong Amibroker là ngôn ngữ xử lý mảng (an array processing language). Nó hoạt động dựa trên các mảng (các dòng/vector) số liệu, khá giống với cách hoạt động của spreadsheet trên excel.