Standards for managing server state (TanStack Query) and local client state (Zustand), and how they interoperate.
This skill defines how Arlis manages data flow between the server and the user interface. It ensures a clean separation between Server State and Local Client State.
Use TanStack Query for anything that lives in the database or comes from an external API.
lib/hooks/queries.tsapi client.// Good: Server state is managed by Query
export function useApplications() {
return useQuery({
queryKey: ['applications'],
queryFn: api.applications.list,
});
}
Use Zustand for UI-only state that doesn't need to be persisted to the database (or is persisted to LocalStorage).
lib/store/ (e.g., lib/store/use-ui-store.ts, lib/store/use-chat-store.ts)// Good: Client state is managed by Zustand
interface UIStore {
activeApplicationId: string | null;
setActiveApplicationId: (id: string | null) => void;
}
export const useUIStore = create<UIStore>((set) => ({
activeApplicationId: null,
setActiveApplicationId: (id) => set({ activeApplicationId: id }),
}));
To coordinate these two, use the "Reference Pattern":
function Dashboard() {
// 1. Get the reference from Zustand
const activeId = useUIStore(s => s.activeApplicationId);
// 2. Pass the reference to TanStack Query
const { data: application } = useApplication(activeId);
return activeId ? <DetailView data={application} /> : <ListView />;
}
const { data } = useQuery(...); useEffect(() => { setZustandData(data) }, [data]) (Sync-loop anti-pattern).useState for state that needs to be accessed by deeply nested children (use Zustand instead).