Claude Code Plugins

Community-maintained marketplace

Feedback

data-and-state-management

@antoncoding/monarch
13
0

Core patterns for data fetching, state management, and user preferences. Use when implementing new features that require getting data from APIs or managing shared state.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

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

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]);