Giới thiệu
Firestore realtime cho phép ứng dụng của bạn lắng nghe thay đổi dữ liệu ngay lập tức. Khi một document được thêm, sửa hoặc xóa, client sẽ nhận được cập nhật tự động mà không cần refresh trang. Hai case study trong tài liệu này giúp bạn thực hành pattern realtime phổ biến:- Ứng dụng chat: Tin nhắn hiển thị đồng bộ trên nhiều thiết bị.
- Ứng dụng quiz ranking: Giáo viên điều khiển bài quiz, học sinh trả lời và bảng xếp hạng cập nhật real-time.
Tài liệu này giả định bạn đã có dự án Next.js với Firebase đã cấu hình. Nếu chưa, xem Thiết lập Firebase và Firestore và tổ chức Data.
Case study 1: Ứng dụng chat
Thiết kế dữ liệu
Bạn cần hai collection chính:Lưu
senderName và senderPhotoURL trong message để tránh phải join với users khi hiển thị. Dữ liệu user có thể thay đổi, nhưng tên trong tin nhắn thường giữ nguyên để giữ ngữ cảnh lịch sử.Gửi tin nhắn
Hàm gửi tin nhắn cần:- Kiểm tra người dùng đã đăng nhập.
- Kiểm tra nội dung tin nhắn không để trống.
- Ghi document vào subcollection
messagescủachat-rooms/{roomId}. - Lưu
senderId,senderName,senderPhotoURLvà timestamp từ server.
Lắng nghe tin nhắn real-time
Hàm đăng ký listener dùngonSnapshot trên subcollection messages, sắp xếp theo createdAt tăng dần. Khi có document mới, sửa hoặc xóa, callback nhận danh sách tin nhắn cập nhật.
Sử dụng trong React component
Trong component React, bạn đăng ký listener khi mount và cleanup khi unmount. Statemessages được cập nhật tự động. Form gửi tin nhắn gọi hàm gửi và xóa input sau khi gửi.
Security Rules cho chat
- Chỉ người dùng đã đăng nhập mới được đọc phòng chat và tin nhắn.
- Người tạo phòng chat mới được sửa/xóa phòng.
- Người gửi tin nhắn mới được sửa/xóa tin nhắn của chính mình.
Prompt mẫu cho vibe-coding (chat app)
Case study 2: Ứng dụng quiz ranking
Mô tả hệ thống
Hệ thống quiz gồm hai vai trò:- Giáo viên: Tạo quiz, phát đề, theo dõi bảng xếp hạng real-time.
- Học sinh: Tham gia quiz bằng auth uid, trả lời câu hỏi, xem điểm của mình cập nhật ngay.
Thiết kế dữ liệu
Lưu
questions trong document quiz vì một bộ đề thường nhỏ hơn 1MB. Nếu đề lớn, tách thành subcollection questions riêng.Màn hình giáo viên: tạo và điều khiển quiz
Giáo viên cần các hàm sau:createQuiz: tạo document quiz với trạng tháiwaiting, lưu tiêu đề, danh sách câu hỏi,createdByvà timestamp.startQuiz: chuyển trạng thái quiz sangactive, ghistartedAt.finishQuiz: chuyển trạng thái quiz sangfinished, ghiendedAt.
Lắng nghe bảng xếp hạng real-time (giáo viên)
Hàm đăng ký listener trên subcollectionparticipants, sắp xếp theo score giảm dần. Mỗi lần dữ liệu thay đổi, callback nhận danh sách participant kèm thứ hạng.
Màn hình học sinh: tham gia và trả lời
Học sinh cần các hàm sau:joinQuiz: tạo hoặc cập nhật document participant của học sinh trong quiz, lưudisplayName, điểm ban đầu bằng 0 và thời gian tham gia.submitAnswer: đọc document quiz để lấy câu hỏi và đáp án đúng, tính điểm, sau đó cập nhật document participant với câu trả lời mới và tổng điểm. Cần kiểm tra quiz đang ở trạng tháiactive.
Theo dõi điểm của chính học sinh
Hàm đăng ký listener trên document participant của người dùng hiện tại. Nếu chưa đăng nhập hoặc chưa tham gia, callback nhận giá trị null.Security Rules cho quiz
- Chỉ người dùng đã đăng nhập mới được đọc quiz.
- Chỉ giáo viên tạo quiz mới được sửa/xóa quiz.
- Học sinh chỉ được tạo/sửa document participant của chính mình.
- Điểm và số câu đã trả lời chỉ được tăng, không được giảm.
- Không cho phép xóa document participant.
Prompt mẫu cho vibe-coding (quiz ranking)
So sánh hai pattern realtime
Best practices
1. Luôn cleanup listener
Trong React, hãy trả về hàm unsubscribe từuseEffect. Nếu không cleanup, listener tiếp tục chạy khi component bị hủy, gây rò rỉ bộ nhớ và tốn chi phí đọc Firestore.
2. Tránh lắng nghe quá nhiều document
Nếu danh sách participant có thể lớn, hãy giới hạn số lượng hiển thị trên bảng xếp hạng và cung cấp nút “Xem thêm”. Sử dụnglimit kết hợp orderBy trong query để giảm số document cần đọc.
3. Tách logic Firestore ra khỏi component
Đặt các hàm nhưsubscribeToMessages, sendMessage, submitAnswer trong thư mục lib/ thay vì viết trực tiếp trong component. Giúp tái sử dụng và dễ test hơn.
4. Validate ở client trước khi ghi
Kiểm tra dữ liệu trước khi gọi Firestore để tránh lỗi và giảm số lần ghi không cần thiết. Ví dụ: từ chối tin nhắn rỗng, kiểm tra quiz đang active trước khi nộp đáp án.5. Dùng server timestamp
Luôn dùng timestamp từ server cho các trườngcreatedAt và updatedAt để thời gian nhất quán trên tất cả client.
6. Cẩn thận với dữ liệu nhạy cảm
Trong quiz, việc lưucorrectIndex trong document quiz có thể bị học sinh đọc được nếu rules không chặt. Nếu cần giấu đáp án, chuyển logic chấm điểm sang Cloud Function hoặc Server Action.
Bài tập thực chiến
Bài 1: Mở rộng chat app
Thêm các tính năng sau vào ứng dụng chat:- Hiển thị “đang nhập…” khi người khác gõ tin nhắn.
- Cho phép xóa tin nhắn của chính mình.
- Hiển thị thời gian gửi theo định dạng “2 phút trước”.
chat-rooms/{roomId}/typing/{userId} để theo dõi trạng thái đang nhập.
Bài 2: Hoàn thiện quiz ranking
Thêm các tính năng sau:- Giáo viên chuyển từng câu hỏi một bằng
currentQuestionIndex. - Học sinh chỉ thấy câu hỏi hiện tại và chỉ được trả lời một lần.
- Sau khi kết thúc, hiển thị podium top 3.