Bài trước, rating và hover state đều sống trong Rating component — component duy nhất cần dùng chúng. Mọi thứ gọn gàng trong một chỗ.
Nhưng thực tế không đơn giản vậy. Bạn có NewPost component chứa form để nhập tiêu đề, và Post component hiển thị tiêu đề đó. Hai component riêng biệt — vậy state nên đặt ở đâu?
Trường hợp đơn giản: state dùng trong cùng component
Khi state chỉ phục vụ một component, đặt thẳng vào component đó là đúng nhất.
Ví dụ — NewPost có một nút toggle để ẩn/hiện phần preview trước khi submit. Không component nào khác cần biết form đang mở hay đóng:
isExpanded không liên quan đến PostList hay Post — giữ local trong NewPost là đúng.
Trường hợp phức tạp: state dùng ở nhiều component
Xét cấu trúc này:
NewPost là nơi phát sinh dữ liệu. Post là nơi cần hiển thị dữ liệu. Hai component này không biết nhau — chúng là anh em (siblings), không phải cha con.
Nếu đặt state trong NewPost:
Post không thể đọc state của NewPost. Trong React, dữ liệu chỉ chạy một chiều: từ cha xuống con qua props — không chạy ngang giữa các anh em.
Giải pháp là đưa state lên component cha chung — PostList. Đây gọi là State Lifting (nâng state lên).
State Lifting trong thực tế
Mở rộng ví dụ đầy đủ — form có cả title lẫn author, bấm Submit thì tạo post mới và đẩy vào danh sách.
Trước tiên, định nghĩa một interface dùng chung cho cả 3 component:
PostList giữ toàn bộ state và handler, truyền xuống từng component con qua props:
NewPost nhận 3 props từ cha — hai handler cho từng field và một hàm submit:
Post chỉ nhận props và hiển thị — không giữ state gì cả:
Luồng dữ liệu hoàn chỉnh:
Quy tắc: đặt state và handler ở đâu?
State đặt ở component thấp nhất có thể — nhưng phải đủ cao để tất cả component cần dùng đều có thể nhận qua props.
Hỏi: “Component nào cần đọc hoặc thay đổi dữ liệu này?”
Chỉ một component → đặt thẳng trong component đó. Nhiều component anh em → đặt trong component cha chung gần nhất. Toàn bộ app → đặt trong Context hoặc global state (Redux, Zustand). Handler đặt cùng chỗ với state — vì handler gọi setter, mà setter phải ở cùng chỗ với state. Rồi truyền handler xuống component con qua props.
Props là gì?
Đây là lúc cần hiểu rõ props — cơ chế để component cha truyền dữ liệu xuống component con.
Props hoạt động giống như tham số của một hàm: cha truyền vào, con nhận và dùng, nhưng không được sửa. Component con chỉ đọc props, không thay đổi trực tiếp — muốn thay đổi thì gọi handler mà cha truyền xuống.
TypeScript giúp định nghĩa rõ props nào được nhận — và props nào là bắt buộc:
Tóm tắt
State chỉ dùng trong một component → đặt local trong component đó. State cần chia sẻ giữa nhiều component → lift lên component cha chung gần nhất. Handler luôn đặt cùng chỗ với state, rồi truyền xuống con qua props. Dữ liệu chỉ chạy một chiều: từ cha xuống con — không bao giờ ngược lại.