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.
Scanned 2/12/2026
Install via CLI
openskills install majiayu000/claude-skill-registry---
name: data-and-state-management
description: 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.
---
## 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`
```typescript
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`
```typescript
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`
```typescript
// 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`
```typescript
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
```typescript
// ❌ 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 });
```
```typescript
// ❌ 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');
```
```typescript
// ❌ 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 }),
}));
```
```typescript
// ❌ Don't chain useEffect
useEffect(() => { setFiltered(data.filter(...)); }, [data]);
useEffect(() => { setSorted(filtered.sort(...)); }, [filtered]);
// ✅ Use useMemo
const processed = useMemo(() => data.filter(...).sort(...), [data]);
```
---
No comments yet. Be the first to comment!