2k1
  • Home
  • Programming
  • System
  • Design
  • Applications
  • Tech
No Result
View All Result
  • Login
2k1
  • Home
  • Programming
  • System
  • Design
  • Applications
  • Tech
No Result
View All Result
2k1
No Result
View All Result

`useState` trong React: Nền Tảng Quản Lý Trạng Thái cho Component Hàm

Nguyen Pham by Nguyen Pham
02/09/2025
in Blog
Reading Time: 14 mins read
A A
0

Bạn đã bao giờ tự hỏi làm thế nào các ứng dụng React có thể phản ứng linh hoạt với hành động của người dùng, thay đổi dữ liệu và cập nhật giao diện mà không cần tải lại trang chưa? Bí mật nằm ở việc quản lý trạng thái (state).

Trong thế giới React hiện đại, useState là một trong những React Hooks quan trọng nhất, cho phép chúng ta thêm trạng thái vào các component hàm (functional components) một cách dễ dàng và hiệu quả. Trước đây, việc này chủ yếu dành cho các component lớp (class components), nhưng với sự ra đời của Hooks, useState đã thay đổi hoàn toàn cách chúng ta xây dựng UI động và tương tác.

Bài viết này sẽ đưa bạn đi sâu vào useState, từ cú pháp cơ bản đến các ví dụ thực tế và những lưu ý quan trọng khi sử dụng.

Bối Cảnh: State trong React là gì?

Trong React, state là một đối tượng JavaScript đơn giản được sử dụng để lưu trữ dữ liệu hoặc thông tin mà có thể thay đổi trong suốt vòng đời của một component. Khi state của một component thay đổi, React sẽ tự động re-render (kết xuất lại) component đó và các component con của nó để cập nhật giao diện người dùng, phản ánh những thay đổi mới nhất.

Hãy tưởng tượng một bộ đếm số, một form nhập liệu, hay một danh sách công việc. Dữ liệu như số đếm hiện tại, giá trị nhập vào, hoặc trạng thái hoàn thành của một công việc đều là các phần của state. Điều này khác với props (properties), vốn là dữ liệu được truyền từ component cha xuống component con và không thể thay đổi bên trong component nhận.

Sự Ra Đời của React Hooks và useState

Trước React 16.8, chỉ có các component lớp mới có thể có state và sử dụng các phương thức vòng đời (lifecycle methods) như componentDidMount hay componentDidUpdate. Tuy nhiên, class components thường đi kèm với một số thách thức:

  • Sử dụng this khó hiểu và dễ gây nhầm lẫn, đặc biệt với những người mới học JavaScript.
  • Khó tái sử dụng logic có trạng thái giữa các component mà không cần các mẫu thiết kế phức tạp như Higher-Order Components (HOCs) hoặc Render Props.
  • Các phương thức vòng đời có thể trở nên phức tạp và khó quản lý khi logic liên quan đến nhiều tác vụ khác nhau (ví dụ: fetching data và setting up event listeners) bị phân tán trong nhiều phương thức.

React Hooks được giới thiệu để giải quyết những vấn đề này, cho phép chúng ta sử dụng state và các tính năng khác của React mà không cần viết một class. useState là Hook đầu tiên và cơ bản nhất, mở ra cánh cửa cho việc quản lý trạng thái trong các functional components.

useState Hoạt Động Như Thế Nào?

Cú Pháp Cơ Bản

Để sử dụng useState, bạn cần import nó từ thư viện react và gọi nó bên trong component hàm của bạn.

import React, { useState } from 'react';

function MyComponent() {
  // Khai báo một biến trạng thái 'count' và hàm cập nhật 'setCount'
  const [count, setCount] = useState(0); 

  // ... phần còn lại của component
}

Hãy phân tích cú pháp này:

  • useState(0): Đây là lời gọi Hook. Nó nhận một đối số duy nhất là giá trị khởi tạo (initial state) cho biến trạng thái của bạn. Trong ví dụ này, 0 là giá trị khởi tạo cho count.
  • const [count, setCount]: Đây là cú pháp phân tách mảng (array destructuring). useState trả về một mảng gồm hai phần tử:
    • count: Biến trạng thái hiện tại. Bạn có thể đặt tên bất kỳ cho nó (ví dụ: name, isVisible).
    • setCount: Một hàm dùng để cập nhật biến trạng thái đó. Theo quy ước, tên hàm này thường là set + Tênbiếntrạng_thái (ví dụ: setName, setIsVisible). Khi bạn gọi hàm này với một giá trị mới, React sẽ re-render component với giá trị trạng thái mới.

Ví Dụ Thực Tế Đầu Tiên: Bộ Đếm Đơn Giản

Hãy xây dựng một bộ đếm số đơn giản để thấy useState hoạt động như thế nào.

import React, { useState } from 'react';

function Counter() {
  // Khai báo biến trạng thái 'count' với giá trị khởi tạo là 0
  const [count, setCount] = useState(0);

  // Hàm xử lý khi nút "Tăng" được nhấn
  const increment = () => {
    setCount(count + 1); // Cập nhật state: tăng giá trị của 'count' lên 1
  };

  // Hàm xử lý khi nút "Giảm" được nhấn
  const decrement = () => {
    setCount(count - 1); // Cập nhật state: giảm giá trị của 'count' xuống 1
  };

  return (
    <div>
      <h1>Bộ Đếm: {count}</h1>
      <button onClick={increment}>Tăng</button>
      <button onClick={decrement}>Giảm</button>
    </div>
  );
}

export default Counter;

Trong ví dụ trên:

  • Chúng ta khai báo count với giá trị ban đầu là 0.
  • Khi nút “Tăng” được nhấn, hàm increment gọi setCount(count + 1). Điều này yêu cầu React cập nhật count lên một giá trị mới.
  • React nhận thấy count đã thay đổi, nó sẽ re-render component Counter.
  • Giao diện người dùng sẽ hiển thị giá trị count mới nhất.

Các Điểm Quan Trọng Cần Nhớ Khi Sử Dụng useState

Giá Trị Khởi Tạo (Initial State)


  • Mọi Kiểu Dữ Liệu: Giá trị khởi tạo có thể là bất kỳ kiểu dữ liệu nào: số, chuỗi, boolean, đối tượng, hoặc mảng.
    javascript

    const [name, setName] = useState('Alice'); // Chuỗi

    const [age, setAge] = useState(30); // Số

    const [isActive, setIsActive] = useState(false); // Boolean

    const [user, setUser] = useState({ id: 1, name: 'Bob' }); // Đối tượng

    const [items, setItems] = useState([]); // Mảng



  • Hàm Khởi Tạo “Lười” (Lazy Initial State): Nếu giá trị khởi tạo của bạn yêu cầu một phép tính phức tạp hoặc tốn kém về tài nguyên, bạn có thể truyền một hàm vào useState. Hàm này chỉ được gọi một lần duy nhất trong lần render đầu tiên của component, giúp tối ưu hiệu suất.


    function calculateInitialValue() {
    console.log('Chỉ chạy một lần!'); // Hàm này chỉ được gọi một lần duy nhất
    return Math.random() * 100;
    }

    function MyComponentWithLazyState() {
    const [value, setValue] = useState(calculateInitialValue); // Truyền hàm, không phải kết quả của hàm

    return <div>Giá trị: {value}</div>;
    }

Cập Nhật State Bất Đồng Bộ (Asynchronous State Updates)

Một điều cực kỳ quan trọng cần nhớ là các hàm set (như setCount) thường cập nhật state một cách bất đồng bộ. Điều này có nghĩa là React có thể nhóm nhiều cập nhật state lại với nhau để tối ưu hiệu suất.

Do đó, nếu bạn cần cập nhật state dựa trên giá trị state trước đó, bạn không nên dựa vào giá trị hiện tại của biến state trực tiếp (ví dụ: count + 1) vì nó có thể không phải là giá trị mới nhất nếu có nhiều cập nhật đang chờ xử lý.

Thay vào đó, hãy truyền một hàm callback vào hàm set. Hàm callback này sẽ nhận giá trị state trước đó làm đối số đầu tiên và trả về giá trị state mới.

function CounterAsync() {
  const [count, setCount] = useState(0);

  const handleClick = () => {
    // Sai lầm phổ biến: có thể không cho kết quả mong muốn nếu gọi nhiều lần liên tiếp
    // setCount(count + 1); 
    // setCount(count + 1); // Sẽ chỉ tăng 1 đơn vị, không phải 2 (do count vẫn là giá trị cũ trong cùng một render cycle)

    // Cách đúng: Sử dụng functional update để đảm bảo lấy giá trị state mới nhất
    setCount(prevCount => prevCount + 1); 
    setCount(prevCount => prevCount + 1); // Sẽ tăng 2 đơn vị
  };

  return (
    <div>
      <h1>Bộ Đếm Bất Đồng Bộ: {count}</h1>
      <button onClick={handleClick}>Tăng 2</button>
    </div>
  );
}

Cập Nhật Đối Tượng và Mảng

Khi state của bạn là một đối tượng hoặc mảng, bạn không thể trực tiếp thay đổi nó (mutation). React yêu cầu bạn phải tạo một bản sao mới của đối tượng hoặc mảng đó và sau đó cập nhật bản sao mới này.

Nếu bạn trực tiếp thay đổi state, React sẽ không nhận ra sự thay đổi và component sẽ không re-render.

Cập Nhật Đối Tượng

Sử dụng toán tử trải rộng (spread operator ...) để tạo một bản sao của đối tượng hiện có và sau đó ghi đè (hoặc thêm) các thuộc tính bạn muốn thay đổi.

function UserProfile() {
  const [user, setUser] = useState({ name: 'John Doe', age: 30, city: 'New York' });

  const updateCity = () => {
    setUser({ 
      ...user, // Sao chép tất cả các thuộc tính hiện có từ đối tượng 'user' cũ
      city: 'London' // Ghi đè thuộc tính 'city' với giá trị mới
    });
  };

  const updateAge = () => {
    setUser(prevUser => ({
      ...prevUser, // Đảm bảo dùng prevUser để lấy giá trị mới nhất của đối tượng
      age: prevUser.age + 1 
    }));
  };

  return (
    <div>
      <h2>Hồ Sơ Người Dùng</h2>
      <p>Tên: {user.name}</p>
      <p>Tuổi: {user.age}</p>
      <p>Thành phố: {user.city}</p>
      <button onClick={updateCity}>Chuyển đến London</button>
      <button onClick={updateAge}>Ăn mừng sinh nhật</button>
    </div>
  );
}

Cập Nhật Mảng

Tương tự, khi cập nhật mảng, bạn cũng cần tạo một bản sao mới của mảng. Các phương thức như map, filter, slice, hoặc toán tử trải rộng ... rất hữu ích.

function TodoList() {
  const [todos, setTodos] = useState([
    { id: 1, text: 'Học React Hooks', completed: false },
    { id: 2, text: 'Viết Blog về useState', completed: false },
  ]);

  const addTodo = (text) => {
    setTodos([
      ...todos, // Sao chép tất cả các todo hiện có
      { id: todos.length + 1, text, completed: false } // Thêm todo mới vào cuối mảng mới
    ]);
  };

  const toggleTodo = (id) => {
    setTodos(
      todos.map(todo =>
        todo.id === id ? { ...todo, completed: !todo.completed } : todo // Tạo bản sao mới của todo cần thay đổi
      )
    );
  };

  return (
    <div>
      <h2>Danh Sách Công Việc</h2>
      <ul>
        {todos.map(todo => (
          <li key={todo.id} 
              style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}
              onClick={() => toggleTodo(todo.id)}>
            {todo.text}
          </li>
        ))}
      </ul>
      <button onClick={() => addTodo('Tập thể dục')}>Thêm "Tập thể dục"</button>
    </div>
  );
}

Nhiều useState trong một Component

Bạn hoàn toàn có thể sử dụng nhiều lời gọi useState trong một component để quản lý các phần trạng thái riêng biệt. Đây là một thực hành tốt vì nó giúp logic của bạn rõ ràng hơn và dễ quản lý hơn.

function UserForm() {
  const [firstName, setFirstName] = useState('');
  const [lastName, setLastName] = useState('');
  const [email, setEmail] = useState('');
  const [isSubmitting, setIsSubmitting] = useState(false);

  const handleSubmit = (e) => {
    e.preventDefault();
    setIsSubmitting(true);
    // Xử lý gửi form (ví dụ: gửi dữ liệu lên API)
    console.log({ firstName, lastName, email });
    setTimeout(() => { // Giả lập quá trình gửi form
      setIsSubmitting(false);
      alert('Form đã được gửi!');
      setFirstName('');
      setLastName('');
      setEmail('');
    }, 1500);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input 
        type="text" 
        value={firstName} 
        onChange={(e) => setFirstName(e.target.value)} 
        placeholder="Tên" 
      />
      <input 
        type="text" 
        value={lastName} 
        onChange={(e) => setLastName(e.target.value)} 
        placeholder="Họ" 
      />
      <input 
        type="email" 
        value={email} 
        onChange={(e) => setEmail(e.target.value)} 
        placeholder="Email" 
      />
      <button type="submit" disabled={isSubmitting}>
        {isSubmitting ? 'Đang gửi...' : 'Gửi'}
      </button>
    </form>
  );
}

Việc sử dụng nhiều useState cho các giá trị độc lập là cách làm được khuyến nghị, thay vì gộp tất cả vào một đối tượng lớn, giúp React tối ưu hóa việc re-render và dễ dàng hơn trong việc tách biệt các logic.

Một Số Sai Lầm Thường Gặp

  • Thay đổi trực tiếp state (mutation): Ví dụ user.age = 31; setUser(user); hoặc todos.push(newTodo); setTodos(todos);. Luôn luôn tạo bản sao mới của đối tượng/mảng khi cập nhật!
  • Quên import useState: import React, { useState } from 'react'; là bắt buộc.
  • Gọi useState bên trong điều kiện, vòng lặp hoặc hàm lồng nhau: React Hooks phải được gọi ở cấp cao nhất của component hàm. Đây là một quy tắc quan trọng của Hooks.
  • Không sử dụng functional update khi state mới phụ thuộc vào state cũ: Dẫn đến lỗi không mong muốn trong các trường hợp cập nhật nhanh hoặc nhiều lần liên tiếp.

Kết Luận

useState là một trong những React Hooks quan trọng nhất, đã cách mạng hóa cách chúng ta quản lý trạng thái trong các component hàm. Với cú pháp đơn giản nhưng mạnh mẽ, nó cho phép bạn thêm tính tương tác và động lực vào ứng dụng React của mình một cách hiệu quả.

Hãy nhớ các quy tắc cơ bản:

  • Khai báo với const [state, setState] = useState(initialState);.
  • Cập nhật state bằng hàm setState.
  • Không thay đổi trực tiếp các đối tượng hoặc mảng, hãy tạo bản sao mới.
  • Sử dụng functional update khi state mới phụ thuộc vào state cũ.
  • Gọi Hooks ở cấp cao nhất của component, không bên trong điều kiện hay vòng lặp.

Nắm vững useState là bước đầu tiên và quan trọng nhất để trở thành một nhà phát triển React thành thạo. Hãy thực hành thường xuyên để làm quen với cách nó hoạt động và bạn sẽ thấy việc xây dựng các ứng dụng React phức tạp trở nên dễ dàng hơn rất nhiều.

Chúc bạn mã hóa vui vẻ!

Previous Post

Hướng Dẫn Cài Đặt và Chạy n8n Với Docker – Tự Động Hóa Công Việc Dễ Dàng

Next Post

Khám Phá Các Thành Phần Cơ Bản Kiến Tạo Nên Ứng Dụng NestJS Mạnh Mẽ

Related Posts

Blog

Khám Phá Các Thành Phần Cơ Bản Kiến Tạo Nên Ứng Dụng NestJS Mạnh Mẽ

by Nguyen Pham
02/09/2025
Hướng Dẫn Cài Đặt và Chạy n8n Với Docker – Tự Động Hóa Công Việc Dễ Dàng
Blog

Hướng Dẫn Cài Đặt và Chạy n8n Với Docker – Tự Động Hóa Công Việc Dễ Dàng

by Nguyen Pham
02/09/2025
GPT OSS: Tương Lai Mã Nguồn Mở Cho AI Ngôn Ngữ
AI

GPT OSS: Tương Lai Mã Nguồn Mở Cho AI Ngôn Ngữ

by Nguyen Pham
17/08/2025
Blog

Facebook, Instagram bất ngờ sập trên diện rộng, liên tục đăng xuất người dùng!

by Nguyen Pham
05/03/2024
Xây dựng todo app với smartcontract
Blog

Web3 là gì?

by Nguyen Pham
30/06/2023
Blog

Chạy ứng dụng react native đầu tiên của bạn

by Nguyen Pham
29/06/2023
Load More
Next Post

Khám Phá Các Thành Phần Cơ Bản Kiến Tạo Nên Ứng Dụng NestJS Mạnh Mẽ

Please login to join discussion
Blog

Khám Phá Các Thành Phần Cơ Bản Kiến Tạo Nên Ứng Dụng NestJS Mạnh Mẽ

by Nguyen Pham
02/09/2025
0

Chào mừng các bạn đến với thế giới của NestJS – một framework Node.js tiến bộ, linh hoạt và cực...

Read more

`useState` trong React: Nền Tảng Quản Lý Trạng Thái cho Component Hàm

02/09/2025
Hướng Dẫn Cài Đặt và Chạy n8n Với Docker – Tự Động Hóa Công Việc Dễ Dàng

Hướng Dẫn Cài Đặt và Chạy n8n Với Docker – Tự Động Hóa Công Việc Dễ Dàng

02/09/2025
GPT OSS: Tương Lai Mã Nguồn Mở Cho AI Ngôn Ngữ

GPT OSS: Tương Lai Mã Nguồn Mở Cho AI Ngôn Ngữ

17/08/2025

Phân tích mã cổ phiếu VCB

26/04/2025

@2021 2k1.org [email protected]

No Result
View All Result
  • Home
  • Review
  • Applications
  • Computers
  • Gaming
  • Microsoft

© 2021 NData

Welcome Back!

Login to your account below

Forgotten Password?

Retrieve your password

Please enter your username or email address to reset your password.

Log In