Bài 3: State & Event – Kiểm soát trạng thái & Xử lý sự kiện

Chào mừng bạn đã quay trở lại! Ở bài trước, chúng ta đã biết cách dùng Props để truyền dữ liệu từ cha xuống con. Nhưng có một điểm chí mạng: Props là dữ liệu chỉ đọc (Read-Only). Nếu bạn muốn làm một tính năng tương tác, ví dụ: người dùng bấm vào nút “Like” (Thích) trên bài viết và số lượt thích phải tăng lên ngay lập tức thì Props sẽ hoàn toàn bất lực.
Để giao diện có thể “biến hình” linh hoạt theo hành động của người dùng, chúng ta cần làm quen với hai mảnh ghép tiếp theo: Event (Sự kiện) và State (Trạng thái).
Xử lý Sự kiện (Event Handling) trong React
Trong HTML truyền thống, bạn thường dùng thuộc tính onclick="handleClick()". Còn trong React, cách viết sẽ có 2 điểm khác biệt nhỏ nhưng cực kỳ quan trọng:
- Tên sự kiện phải viết theo chuẩn camelCase (ví dụ:
onClick,onChange,onSubmit). - Bạn truyền vào một hàm xử lý nằm trong cặp dấu ngoặc nhọn
{}chứ không phải một chuỗi văn bản.
Mở lại file src/PostCard.jsx từ bài trước, hãy thử thêm một sự kiện khi người dùng click vào nút “Đọc tiếp”:
// src/PostCard.jsx
function PostCard({ title, date }) {
// 1. Khai báo hàm xử lý sự kiện
const handleAlert = () => {
alert(`Bạn đang mở bài viết: ${title}`);
};
return (
<div style={{ border: '1px solid #ccc', padding: '15px', borderRadius: '8px', margin: '10px 0' }}>
<h3>{title}</h3>
<p>Ngày đăng: {date}</p>
{/* 2. Gắn hàm vào sự kiện onClick */}
<button onClick={handleAlert}>Xem thêm</button>
</div>
);
}
export default PostCard;
⚠️ Lưu ý kinh điển: Khi gắn vào onClick, bạn chỉ viết tên hàm là {handleAlert}, tuyệt đối không thêm cặp dấu ngoặc đơn thành {handleAlert()}. Nếu thêm (), hàm sẽ bị kích hoạt ngay lập tức khi trang web vừa tải xong chứ không đợi người dùng click.
State là gì? Tại sao phải cần đến useState?
Bây giờ, hãy thử làm một tính năng thực tế hơn: Thêm một nút “Thích ❤️” và hiển thị số lượt thích.
Nếu bạn chỉ khai báo một biến số thông thường như let likes = 0 và cộng dồn nó mỗi khi click, số biến có tăng nhưng giao diện trên màn hình sẽ đứng im. Lý do là vì React không hề biết biến đó thay đổi để vẽ lại (re-render) giao diện.
Để bắt React phải vẽ lại giao diện mỗi khi dữ liệu thay đổi, chúng ta phải dùng đến State thông qua một công cụ gọi là Hook useState.
Thực hành kiểm soát trạng thái với useState
Hãy cập nhật lại file src/PostCard.jsx để biến số lượt thích thành một trạng thái (State):
// src/PostCard.jsx
import { useState } from 'react'; // 1. Import useState từ thư viện React
function PostCard({ title, date }) {
// 2. Khai báo State, trong đó:
// likes (giá trị hiện tại), setLikes (hàm để cập nhật)
// Số 0 trong ngoặc là giá trị khởi tạo ban đầu của lượt thích
const [likes, setLikes] = useState(0);
const handleLike = () => {
// 3. Sử dụng hàm setLikes để cập nhật dữ liệu mới
setLikes(likes + 1);
};
return (
<div style={{ border: '1px solid #ccc', padding: '15px', borderRadius: '8px', margin: '10px 0' }}>
<h3>{title}</h3>
<p>Ngày đăng: {date}</p>
{/* Hiển thị số lượt thích động theo giá trị state likes */}
<p>Lượt thích: {likes} ❤️</p>
<button onClick={handleLike}>
Thích
</button>
</div>
);
}
export default PostCard;
Bây giờ bạn quay lại trình duyệt và bấm thử nút “Thích” xem. Mỗi lần click, số lượt thích sẽ nhảy lên ngay lập tức!
Cơ chế hoạt động phía sau cực kỳ đơn giản: Khi bạn gọi hàm setLikes(), React sẽ nhận được tín hiệu: “Này, trạng thái (state) của PostCard vừa thay đổi rồi! Cập nhật lại đi.”. Ngay lập tức, nó re-render component PostCard với giá trị likes mới và phần giao diện cũng được cập nhật tương ứng trên màn hình ngay lúc đó.

Phân biệt nhanh giữa Props và State
Để không bao giờ bị nhầm lẫn khi làm việc với React, bạn chỉ cần nhớ quy tắc bỏ túi sau:
| Đặc điểm | Props | State |
|---|---|---|
| Nguồn gốc | Do Component Cha truyền xuống. | Do chính Component đó tự khởi tạo và quản lý. |
| Khả năng chỉnh sửa | Chỉ đọc (Read-Only), không thể tự sửa đổi ở component nhận. | Có thể thay đổi linh hoạt thông qua hàm cập nhật (set...). |
| Mục đích | Giúp cấu hình và truyền dữ liệu cho giao diện tĩnh. | Giúp lưu trữ dữ liệu tương tác, biến đổi theo thời gian. |
Để dễ hình dung về mạch đi của dữ liệu trong React tính đến thời điểm này, bạn có thể nhìn vào sơ đồ dòng chảy (flow) đơn giản sau:
[Props] (Dữ liệu từ Cha) │ ▼[Component Con] ── (Kích hoạt Event) ──► [State cục bộ] (useState) ▲ │ │ ▼ └─────────── [Re-render View] ────────────┘
Trong đó:
- Props: Là dữ liệu đầu vào cố định được truyền từ component cha xuống.
- Component: Nhận Props để hiển thị, đồng thời tự quản lý một trạng thái nội bộ (State).
- State: Khi người dùng tương tác (sinh ra Event), State sẽ thay đổi và kích hoạt vòng lặp ép Component phải Re-render để cập nhật lại giao diện mới.
Lời kết
Qua bài viết này, bạn đã chính thức làm chủ được:
- Cách bắt các sự kiện từ người dùng bằng
onClick. - Cách dùng
useStateđể lưu trữ dữ liệu động và điều khiển việc React re-render giao diện.
Vậy còn khi component vừa xuất hiện, làm sao để nó tự động gọi API hoặc chạy bộ đếm giờ ngầm? Cùng đón xem Bài 4: React Hooks – Kiểm soát vòng đời component nhé!





