Claude-skill-registry data-and-state-management
Core patterns for data fetching, state management, and user preferences. Use when implementing new features that require getting data from Our APIs, Morpho API, on-chain states or managing shared state.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/data-and-state-management" ~/.claude/skills/majiayu000-claude-skill-registry-data-and-state-management && rm -rf "$T"
manifest:
skills/data/data-and-state-management/SKILL.mdsource content
Quick Reference
State Management Decision Tree
External Data (API, blockchain) → React Query User Preferences (persist across refresh) → Zustand + persist Shared UI State (modals, selections, operations) → Zustand Computed/Derived → useMemo Hook Local UI State (single component) → useState
Detailed Patterns
Data Flow
1. Try Morpho API (if network supported) ↓ fails 2. Fallback to The Graph Subgraph ↓ optional 3. Enhance with on-chain RPC data
React Query (External Data)
Location:
src/hooks/queries/use{Entity}Query.ts
export const useMarketsQuery = () => { return useQuery({ queryKey: ['markets'], queryFn: fetchMarkets, staleTime: 5 * 60 * 1000, }); }; // Usage const { data, isLoading } = useMarketsQuery();
Zustand + Persist (User Preferences)
Location:
src/stores/use{Feature}{State}.ts
export const useMarketsFilters = create( persist( (set) => ({ selectedNetwork: null, setSelectedNetwork: (network) => set({ selectedNetwork: network }), }), { name: 'monarch_store_marketsFilters' } ) ); // Usage - separate selectors for primitives const network = useMarketsFilters((s) => s.selectedNetwork); const setNetwork = useMarketsFilters((s) => s.setSelectedNetwork);
Zustand (Shared UI State)
Location:
src/stores/use{Feature}Store.ts
// Modal state export const useVaultModalStore = create((set) => ({ isOpen: false, open: () => set({ isOpen: true }), close: () => set({ isOpen: false }), })); // Selection state export const useTableSelectionStore = create((set) => ({ selectedIds: [], toggleSelection: (id) => set((state) => ({ selectedIds: state.selectedIds.includes(id) ? state.selectedIds.filter((i) => i !== id) : [...state.selectedIds, id] })), clearSelection: () => set({ selectedIds: [] }), }));
Derived Data Hooks
Location:
src/hooks/use{Processed|Filtered}{Entity}.ts
export const useFilteredMarkets = () => { const { data } = useMarketsQuery(); const searchQuery = useMarketsFilters((s) => s.searchQuery); return useMemo(() => { return data .filter((m) => m.symbol.includes(searchQuery)) .sort((a, b) => b.tvl - a.tvl); }, [data, searchQuery]); };
Anti-Patterns
// ❌ Don't fetch in Context const Provider = () => { useEffect(() => { fetch().then(setData); }, []); return <Context.Provider value={data}>{children}</Context.Provider>; }; // ✅ Use React Query const useDataQuery = () => useQuery({ queryKey: ['data'], queryFn: fetch });
// ❌ Don't create objects in selectors (infinite loop) const filters = useStore((s) => s.filters ?? { min: '0' }); // ✅ Return primitives const min = useStore((s) => s.filters?.min ?? '0');
// ❌ Don't use useState for shared state const [modalOpen, setModalOpen] = useState(false); // Then pass through 3 levels of props... // ✅ Use Zustand for shared UI state const useModalStore = create((set) => ({ isOpen: false, open: () => set({ isOpen: true }), }));
// ❌ Don't chain useEffect useEffect(() => { setFiltered(data.filter(...)); }, [data]); useEffect(() => { setSorted(filtered.sort(...)); }, [filtered]); // ✅ Use useMemo const processed = useMemo(() => data.filter(...).sort(...), [data]);