Khi bước chân vào thế giới React, bên cạnh props, bạn sẽ ngay lập tức nghe thấy một khái niệm cốt lõi, một trụ cột không thể thiếu: state. Nếu ví một component React như một cơ thể sống, thì props giống như DNA được truyền từ cha mẹ, còn state chính là ký ức, là trạng thái cảm xúc, là những gì thay đổi bên trong cơ thể đó theo thời gian và tương tác.
Hiểu rõ state không chỉ là biết một phần của React, mà là nắm được chìa khóa để xây dựng các ứng dụng web động, có tính tương tác cao và mang lại trải nghiệm người dùng tuyệt vời.
Bài viết này sẽ là tài liệu toàn diện giúp bạn giải mã tất cả về state: từ khái niệm cơ bản nhất, cách sử dụng qua hook useState
, những quy tắc vàng cần tuân thủ, cho đến việc phân biệt với props và quản lý các state phức tạp.
1. State là gì? Một cách giải thích dễ hiểu nhất
Hãy tưởng tượng một chiếc công tắc đèn. Nó có hai trạng thái: BẬT và TẮT. Giao diện người dùng (UI) của bạn sẽ hiển thị hình ảnh bóng đèn sáng khi trạng thái là "BẬT" và hình ảnh bóng đèn tối khi trạng thái là "TẮT".
Trong React, State là một đối tượng JavaScript dùng để lưu trữ dữ liệu nội bộ của một component. Dữ liệu này có thể thay đổi theo thời gian, thường là do tương tác của người dùng.
Điểm kỳ diệu và quan trọng nhất cần nhớ là: Khi state của một component thay đổi, React sẽ tự động render lại (re-render) component đó để cập nhật giao diện người dùng (UI) theo dữ liệu mới.
Đây chính là cơ chế tạo nên tính "phản ứng" (Reactive) của React. Bạn không cần phải trực tiếp thay đổi HTML bằng tay. Bạn chỉ cần thay đổi state, và React sẽ lo phần còn lại.
2. Tại sao chúng ta cần State?
Nếu không có state, ứng dụng của bạn sẽ chỉ là một trang web tĩnh, giống như một tờ báo in. Mọi thứ đều cố định. State mang lại sự sống cho ứng dụng bằng cách cho phép nó:
- Phản hồi lại tương tác của người dùng: Bấm một nút, điền vào một form, bật/tắt một chế độ...
- Hiển thị dữ liệu thay đổi theo thời gian: Một chiếc đồng hồ đếm ngược, thông báo mới, dữ liệu được tải về từ máy chủ (API).
- Kiểm soát luồng hoạt động của component: Một modal có thể được hiển thị hoặc ẩn đi, một menu có thể được mở hoặc đóng.
3. "Người bạn đồng hành" không thể thiếu: useState
Trong React hiện đại với Functional Components, chúng ta quản lý state bằng một hook đặc biệt tên là useState
. Hook này là cách đơn giản và phổ biến nhất để thêm state vào component của bạn.
Cú pháp của useState
import { useState } from 'react'
function MyComponent() {
const [state, setState] = useState(initialValue)
// ...
}
Hãy cùng "mổ xẻ" cú pháp này:
useState()
: Là một hàm bạn gọi bên trong functional component để tạo ra một "mẩu" state.initialValue
: Là giá trị khởi tạo của state. Nó có thể là bất cứ thứ gì: một con số, một chuỗi, một boolean (true
/false
), một object, một array... Giá trị này chỉ được dùng trong lần render đầu tiên.state
: Là biến chứa giá trị hiện tại của state. Trong ví dụ trên, nó sẽ có giá trị làinitialValue
ở lần render đầu tiên.setState
: Là hàm bạn dùng để cập nhật giá trị của state. Khi bạn gọi hàm này với một giá trị mới, React sẽ lên lịch render lại component.
Ví dụ kinh điển: Bộ đếm (Counter)
Đây là ví dụ kinh điển của state trong React.
import React, { useState } from 'react'
function Counter() {
// 1. Khai báo state 'count' với giá trị ban đầu là 0
const [count, setCount] = useState(0)
// Hàm xử lý khi nhấn nút tăng
const handleIncrement = () => {
// 2. Dùng hàm setCount để cập nhật state
setCount(count + 1)
}
// Hàm xử lý khi nhấn nút giảm
const handleDecrement = () => {
// 3. Cũng dùng hàm setCount để cập nhật state
setCount(count - 1)
}
return (
<div>
<h1>Bộ đếm</h1>
{/* 3. Hiển thị giá trị hiện tại của state */}
<p>Số lượt bấm hiện tại: {count}</p>
<button onClick={handleIncrement}>Tăng (+)</button>
<button onClick={handleDecrement}>Giảm (-)</button>
</div>
)
}
export default Counter
Trong ví dụ này:
- Ta khai báo một state tên là
count
với giá trị ban đầu là0
. - Khi người dùng nhấn nút "Tăng", hàm
handleIncrement
được gọi. Bên trong, hàmsetCount(count + 1)
được thực thi. - React nhận thấy yêu cầu thay đổi state. Nó sẽ render lại component
Counter
. - Trong lần render lại này, biến
count
giờ sẽ có giá trị mới (ví dụ là1
), và giao diện sẽ được cập nhật để hiển thị<p>Số lượt bấm hiện tại: 1</p>
.
4. Những "nguyên tắc vàng" khi làm việc với State
Để làm việc hiệu quả và tránh các lỗi khó tìm, hãy luôn ghi nhớ các quy tắc sau:
Không bao giờ thay đổi State trực tiếp
Đây là lỗi phổ biến nhất của người mới bắt đầu.
// ❌ SAI!
// Đừng bao giờ làm thế này. React sẽ không biết để render lại.
this.state.comment = 'Hello' // Đối với Class Component
myState.name = 'John' // Đối với Functional Component
// ✅ ĐÚNG!
// Luôn dùng hàm setter (setState) được cung cấp.
this.setState({ comment: 'Hello' }) // Đối với Class Component
setMyState({ ...myState, name: 'John' }) // Đối với Functional Component
Tại sao? React chỉ kích hoạt việc render lại khi hàm setState
được gọi. Việc thay đổi trực tiếp sẽ không thông báo cho React biết, dẫn đến dữ liệu thay đổi nhưng giao diện không được cập nhật.
Cập nhật State có thể là bất đồng bộ
React có thể gộp nhiều lệnh setState
lại với nhau thành một lần cập nhật duy nhất để tối ưu hiệu năng. Điều này có nghĩa là bạn không thể tin tưởng vào giá trị của state ngay sau khi vừa gọi setState
.
function Counter() {
const [count, setCount] = useState(0)
const handleTripleClick = () => {
// Nếu count đang là 0, bạn nghĩ count sẽ là 3?
setCount(count + 1) // count vẫn là 0 ở đây
setCount(count + 1) // count vẫn là 0 ở đây
setCount(count + 1) // count vẫn là 0 ở đây
// Kết quả cuối cùng: count sẽ chỉ tăng lên 1!
}
}
Giải pháp: Khi giá trị state mới phụ thuộc vào giá trị state cũ, hãy truyền một hàm vào bên trong hàm setState
. Hàm này sẽ nhận vào giá trị state trước đó prevState
và trả về giá trị mới.
// ✅ ĐÚNG!
const handleTripleClick = () => {
setCount((prevCount) => prevCount + 1)
setCount((prevCount) => prevCount + 1)
setCount((prevCount) => prevCount + 1)
// Kết quả: count sẽ tăng lên 3 chính xác!
}
State là cục bộ và riêng tư
State của một component là hoàn toàn riêng tư. Không một component nào khác có thể truy cập trực tiếp vào state của nó, kể cả component cha hay con. Cách duy nhất để chia sẻ thông tin là truyền nó xuống dưới dạng props
(từ cha xuống con).
5. State vs. Props trong React
Đây là điểm gây nhầm lẫn cho nhiều người. Hãy làm rõ nó bằng một bảng so sánh:
Tiêu chí | State | Props |
---|---|---|
Nguồn gốc | Được quản lý bên trong component. | Được truyền từ bên ngoài vào component (bởi component cha). |
Khả năng thay đổi | Có thể thay đổi bởi chính component đó (thông qua setState ). | Không thể thay đổi (read-only/immutable). Giống như tham số của hàm. |
Mục đích | Để lưu trữ dữ liệu thay đổi theo thời gian, tạo ra sự tương tác. | Để cấu hình và truyền dữ liệu cho component con. |
Luồng dữ liệu | Cục bộ, chỉ tồn tại trong component. | "Top-down" - từ cha xuống con. |
Một câu "thần chú" dễ nhớ: Props được truyền vào component (như tham số của hàm), trong khi state được quản lý bên trong component (như biến được khai báo trong hàm).
6. Mở rộng: Quản lý State phức tạp
Khi ứng dụng của bạn lớn dần, useState
đôi khi là chưa đủ. React và hệ sinh thái của nó cung cấp các công cụ mạnh mẽ hơn:
- Reducer: Một hook khác của React là
useReducer
, phù hợp để quản lý các state object phức tạp với nhiều hành động cập nhật khác nhau (tương tự như Redux). - Context API: Giải pháp của React để chia sẻ state xuyên suốt cây component mà không cần phải "khoan" props (prop drilling) qua nhiều cấp.
- Thư viện quản lý State: Đối với các ứng dụng cực lớn, các thư viện như Redux Toolkit, Zustand, hoặc Jotai cung cấp các giải pháp mạnh mẽ và có cấu trúc để quản lý state toàn cục (global state).
Nếu bạn đã đọc đến đây, xin chúc mừng! Bạn không chỉ biết "state là gì" mà còn hiểu được "tại sao", "như thế nào" và "khi nào" nên sử dụng nó.
Hãy nhớ rằng:
- State là bộ nhớ của component.
useState
là công cụ chính để tạo và cập nhật state.- Luôn tôn trọng các quy tắc về tính bất biến và cập nhật bất đồng bộ.
- Hiểu rõ sự khác biệt giữa
state
vàprops
là nền tảng vững chắc.
Nắm vững state chính là bạn đã nắm vững được cách "thổi hồn" vào các ứng dụng React, biến chúng từ những trang tĩnh vô tri thành những trải nghiệm sống động và đầy tương tác.
Chúc bạn thành công trên hành trình chinh phục React!