React Query giải quyết race conditions tự động: auto-cancel request cũ khi queryKey thay đổi (cần pass signal vào fetch), deduplication (nhiều components cùng query chỉ 1 request), luôn lấy result mới nhất.
React Query giải quyết race conditions tự động: Race condition xảy ra khi nhiều requests cùng lúc và response muộn hơn override response mới hơn — vấn đề kinh điển với useEffect + fetch.
React Query giải quyết ở nhiều tầng:
- Cancellation: khi queryKey thay đổi (ví dụ search input), React Query abort request cũ nếu queryFn nhận và dùng signal —
queryFn: ({ signal }) => fetch(url, { signal }). - Deduplication: nếu query đang fetch và component khác request cùng queryKey, React Query không gửi thêm request mà share kết quả — chỉ 1 request.
- Strict mode safety: React Query không commit kết quả của request đã bị replace bởi request mới hơn.
enabledpattern cho dependent queries:enabled: !!userIdđảm bảo không fetch với stale userId
Comparison với useEffect: với useEffect bạn phải manually track và cancel với cleanup function return () => { cancelled = true } hoặc AbortController — dễ leak và dễ có bugs.
React Query làm tất cả điều này tự động miễn là queryFn sử dụng signal.
React Query handles race conditions automatically: auto-cancels stale requests when the queryKey changes (pass signal to fetch), deduplicates (multiple components with the same query = 1 request), and always uses the latest result.
- Race conditions occur when multiple requests are in flight and responses arrive out of order.
- React Query handles this automatically in several ways: Automatic cancellation — when a query refetches (key change, window focus), the previous in-flight request is cancelled via AbortSignal, so only the latest response updates the cache; Deduplication — if multiple components subscribe to the same query simultaneously, only one network request is made; Stale closure prevention — React Query's internal state management ensures the latest response always wins even without AbortSignal support from the fetcher.
- For mutations: use mutateAsync with proper error handling; avoid multiple simultaneous mutations on the same resource.
- Optimistic updates with onMutate/onError rollback pattern handles the case where a mutation fails after the UI was already updated optimistically.