The State Management Confusion
Developers often store all application data in global state stores like Redux or Zustand. This leads to unnecessary boilerplate for managing fetching flags, caching, and cache invalidation.
1. Server State vs Client State
- Server State: Data owned by external databases (user profiles, blog posts). Asynchronous and subject to becoming stale.
- Client State: Pure UI state operating locally in the browser (modal open/closed, active tab index, dark mode toggle).
2. TanStack Query for Server State
Use TanStack Query for data fetching, caching, deduplication, and automatic retries:
import { useQuery } from '@tanstack/react-query';
export function useUserProfile(userId: string) {
return useQuery({
queryKey: ['user', userId],
queryFn: () => fetch(`/api/users/${userId}`).then(res => res.json()),
staleTime: 1000 * 60 * 5,
});
}
3. Zustand for Client State
Use Zustand for lightweight local UI state management:
import { create } from 'zustand';
interface UIStore {
isSidebarOpen: boolean;
toggleSidebar: () => void;
}
export const useUIStore = create<UIStore>((set) => ({
isSidebarOpen: false,
toggleSidebar: () => set((state) => ({ isSidebarOpen: !state.isSidebarOpen })),
}));
Conclusion
Decoupling asynchronous server state from local UI state ensures cleaner architecture and maintainable React applications.