1. 09:25 14/10/2026
Khi phát triển ứng dụng chạy cùng một codebase trên web (Next.js) và mobile (React Native/Expo), việc hỗ trợ chế độ offline không chỉ cải thiện trải nghiệm người dùng mà còn giảm tải cho máy chủ. Dưới đây là quy trình thực tế đã áp dụng trong một dự án thương mại điện tử đa nền tảng.
1. Chọn thư viện lưu trữ cục bộ
- Web: IndexedDB qua idb‑keyval (nhẹ, API Promise).
- Mobile: SQLite qua expo‑sqlite hoặc WatermelonDB (hỗ trợ quan hệ và migration).
Cả hai đều expose cùng một interface `LocalStore` (get, set, delete, query) để code dùng chung không phân biệt nền tảng.
2. Xác định dữ liệu cần offline
- Danh mục sản phẩm, giỏ hàng, thông tin người dùng, lịch sử đơn hàng.
- Dữ liệu tĩnh (cấu hình, bản dịch) cache bằng Service Worker (web) và `expo-asset` (mobile).
3. Kiến trúc đồng bộ
- Mọi thay đổi (thêm/sửa/xoá) trước tiên ghi vào LocalStore, sau đó đẩy vào hàng đợi `SyncQueue` (mảng đơn giản lưu `{type, payload, timestamp}`).
- Worker/background task định kỳ (mỗi 30 giây hoặc khi network thay đổi) xử lý queue:
a. Gọi API REST/GraphQL với `optimistic update` đã có local.
b. Nếu thành công → xóa item khỏi queue, cập nhật `lastSyncedAt`.
c. Nếu lỗi 4xx → ghi log, giữ queue để retry sau; lỗi 5xx → exponential backoff.
- Sử dụng `react-query` (TanStack Query) để quản lý cache server; khi offline, query trả về data từ LocalStore.
4. Xử lý xung đột
- Mỗi bản ghi có `version` (integer) và `updatedAt`.
- Khi push lên server, gửi kèm `version` hiện tại. Server so sánh: nếu khớp → chấp nhận, trả về version mới; nếu không → trả về `conflict` kèm data mới nhất.
- Client nhận conflict: merge tự động cho các trường không xung đột (số lượng giỏ hàng) và hiển thị dialog cho người dùng quyết định các trường quan trọng (địa chỉ giao hàng).
5. Kiểm thử thực tế
- Tắt network trên Chrome DevTools và iOS Simulator, thực hiện thêm sản phẩm vào giỏ, đóng app, bật network lại → giỏ hàng đồng bộ chính xác.
- Sử dụng `jest` + `msw` để mock network offline/online và verify queue processing.
Lời khuyên áp dụng ngay:
- Đóng gói LocalStore và SyncQueue vào package `shared/data` của monorepo để cả web và mobile dùng chung.
- Bật `workbox` cho Next.js để cache static assets tự động.
- Theo dõi metric `syncSuccessRate` và `conflictRate` qua OpenTelemetry để phát hiện sớm vấn đề.
Với cách tiếp cận này, ứng dụng vẫn hoạt động mượt mà khi mất kết nối, đồng thời đảm bảo tính nhất quán dữ liệu khi quay lại online.