Câu hỏi quyết định State Stack của bạn
Đừng so sánh Redux với React Query nữa.
Việc này giống như hỏi bạn muốn búa hay tua vít trước khi biết bạn định xây dựng cái gì vậy. Redux, React Query và Zustand đều giải quyết các vấn đề khác nhau.
Quyết định thực sự đến từ một câu hỏi duy nhất: Ai là chủ sở hữu của "nguồn sự thật" (source of truth) cho mỗi phần state?
Bạn có hai loại sự thật.
- Sự thật được sở hữu (Owned Truth) Client là nguồn. Điều này bao gồm những thứ như:
- Sidebar có đang mở không?
- Chủ đề (theme) hiện tại là gì?
- Bước nào của form đang hoạt động? State này tồn tại và thay đổi dựa trên các quyết định cục bộ của bạn. Nó không cần phải xác minh lại với server.
- Sự thật được mượn (Borrowed Truth) Nguồn nằm ở server. Client chỉ giữ một bản sao (mirror) của dữ liệu đó. Dữ liệu này có thể thay đổi mà bạn không hề hay biết. Công việc của bạn là quản lý:
- Độ cũ của dữ liệu (Staleness)
- Vô hiệu hóa dữ liệu (Invalidation)
- Tải lại dữ liệu (Refetching)
- Bộ nhớ đệm (Caching)
Hầu hết các lập trình viên gặp khó khăn vì họ dùng một công cụ cho cả hai mục đích. Khi bạn cố gắng quản lý "sự thật được mượn" trong một client-side reducer, kết quả là bạn đang viết lại React Query một cách vụng về. Bạn phải tự viết thủ công các trạng thái loading, xử lý lỗi và caching. Điều này tạo ra một lượng lớn mã nguồn không cần thiết.
Hãy chia tách chúng để giành chiến thắng.
Dùng React Query cho "sự thật được mượn". Nó xử lý các công việc đồng bộ hóa phức tạp. Dùng Zustand cho "sự thật được sở hữu". Nó xử lý việc lưu trữ các giá trị đơn giản mà không cần các thủ tục rườm rà.
Đừng đổ dữ liệu từ server vào Zustand. Hãy giữ ranh giới đó thật rõ ràng.
Còn Redux và Sagas thì sao? Sagas không dùng để fetch dữ liệu. Chúng dùng để điều phối các quy trình phức tạp theo thời gian. Hãy dùng chúng nếu ứng dụng của bạn xử lý:
- Các luồng đồng thời có thể hủy (Concurrent, cancellable flows).
- Các luồng websocket thời gian thực (Real-time websocket streams).
- Các máy trạng thái phức tạp (Complex state machines).
Nếu bạn dùng React Query mà Sagas của bạn chẳng làm gì cả, thì bạn không cần chúng.
Có một cách thứ ba: Hợp nhất (Unification). RTK Query và Redux cho phép bạn giữ mọi thứ trong một store duy nhất. Điều này mang lại cho bạn một bản chụp (snapshot) duy nhất của toàn bộ ứng dụng. Nó giúp việc debug, đăng xuất và lưu trữ ngoại tuyến (offline persistence) trở nên dễ dàng hơn nhiều.
Hãy chọn con đường dựa trên nhu cầu của bạn:
- React Query + Zustand: Tốt nhất cho các nhóm nhỏ cần sự phức tạp thấp.
- Redux + Sagas: Tốt nhất cho các lĩnh vực có độ đồng thời cao như các ứng dụng giao dịch.
- Chỉ dùng RTK: Tốt nhất cho các đội ngũ doanh nghiệp lớn cần một nguồn sự thật duy nhất.
Trước khi chọn một công cụ, hãy tự hỏi liệu state đó có thực sự cần phải nằm ở client hay không. Server Components đang đưa phần lớn logic này trở lại server.
Hãy xác định xem ai là chủ sở hữu của sự thật trước. Công cụ sẽ theo sau.