frontend
Zustand: none of Redux's ceremony, and the mess that invites
Zustand: none of Redux's ceremony, and the mess that invites
A small state library that skips almost all of Redux's ceremony — no providers, no actions/reducers/dispatch boilerplate, no context re-render issues. A store is just a function:
const useQueueStore = create<QueueState>((set) => ({
tokens: [],
addToken: (token) => set((state) => ({ tokens: [...state.tokens, token] })),
}));
const tokens = useQueueStore((state) => state.tokens);
Over React Context: Context re-renders every consumer whenever any part of the value changes, unless it's split into many small, carefully memoised contexts — which most people don't do correctly, and it gets unwieldy past a couple of pieces of shared state. Zustand's selector pattern re-renders a component only when the slice it selected changes — genuinely better performance for free, without the manual memoisation discipline Context needs to get the same result.
Over Redux: Redux's value is strict, traceable, time-travel-debuggable state for very large apps with many contributors, and the ceremony only pays for itself at that scale. For a handful of focused apps with fairly contained state — current queue, current token, connection status — that ceremony is mostly overhead.
For a realtime, multi-device app specifically, most of the frontend state is "what does the live connection say is true right now." Zustand stores work well as the landing target for socket handlers — an incoming event updates the store directly, and every component reading it re-renders automatically:
socket.on("queueUpdated", (data) => {
useQueueStore.getState().setQueue(data);
});
The trade-off: Zustand doesn't enforce much structure. Nothing stops a codebase ending up with many small, ad-hoc stores with unclear boundaries unless there's a deliberate convention — one store per real domain concept, not one per component. The lack of ceremony that makes it fast to use is the same thing that won't stop a mess if nobody's paying attention to store boundaries as the app grows.