supabase
Handles the full Supabase workflow from schema changes to deployment, with built-in security guardrails that catch common traps like RLS...
zustand-store-patterns
Use when creating and managing Zustand stores for React state management. Covers store creation, selectors, actions, and basic usage patterns.
Full skill instructions
Zustand is a small, fast, and scalable state management solution for React. It uses a simplified flux principles with a hooks-based API.
A Zustand store is created using the create function:
import { create } from 'zustand'
interface BearStore {
bears: number
increasePopulation: () => void
removeAllBears: () => void
}
const useBearStore = create<BearStore>((set) => ({
bears: 0,
increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
removeAllBears: () => set({ bears: 0 }),
}))
function BearCounter() {
const bears = useBearStore((state) => state.bears)
return <h1>{bears} around here...</h1>
}
function Controls() {
const increasePopulation = useBearStore((state) => state.increasePopulation)
return <button onClick={increasePopulation}>Add bear</button>
}
Zustand provides two ways to update state:
// Replace state
set({ bears: 5 })
// Merge state (shallow merge)
set((state) => ({ bears: state.bears + 1 }))
Select only the state you need to prevent unnecessary re-renders:
// ❌ Bad: Component re-renders on any state change
function BadComponent() {
const store = useBearStore()
return <div>{store.bears}</div>
}
// ✅ Good: Component only re-renders when bears changes
function GoodComponent() {
const bears = useBearStore((state) => state.bears)
return <div>{bears}</div>
}
Keep your store organized by separating data from actions:
interface TodoStore {
// State
todos: Todo[]
filter: 'all' | 'active' | 'completed'
// Actions
addTodo: (text: string) => void
toggleTodo: (id: string) => void
removeTodo: (id: string) => void
setFilter: (filter: TodoStore['filter']) => void
}
const useTodoStore = create<TodoStore>((set) => ({
todos: [],
filter: 'all',
addTodo: (text) =>
set((state) => ({
todos: [...state.todos, { id: Date.now().toString(), text, completed: false }],
})),
toggleTodo: (id) =>
set((state) => ({
todos: state.todos.map((todo) =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
),
})),
removeTodo: (id) =>
set((state) => ({
todos: state.todos.filter((todo) => todo.id !== id),
})),
setFilter: (filter) => set({ filter }),
}))
When selecting multiple values, use shallow from zustand/shallow:
import { create } from 'zustand'
import { shallow } from 'zustand/shallow'
const useStore = create<Store>((set) => ({
nuts: 0,
honey: 0,
increaseNuts: () => set((state) => ({ nuts: state.nuts + 1 })),
increaseHoney: () => set((state) => ({ honey: state.honey + 1 })),
}))
// ✅ Using shallow comparison
function Component() {
const { nuts, honey } = useStore(
(state) => ({ nuts: state.nuts, honey: state.honey }),
shallow
)
return <div>{nuts} nuts, {honey} honey</div>
}
For complex applications, split stores into logical slices:
interface UserSlice {
user: User | null
login: (credentials: Credentials) => Promise<void>
logout: () => void
}
interface CartSlice {
items: CartItem[]
addItem: (item: Product) => void
removeItem: (id: string) => void
clearCart: () => void
}
const createUserSlice = (set: StateCreator<UserSlice>) => ({
user: null,
login: async (credentials) => {
const user = await api.login(credentials)
set({ user })
},
logout: () => set({ user: null }),
})
const createCartSlice = (set: StateCreator<CartSlice>) => ({
items: [],
addItem: (product) =>
set((state) => ({
items: [...state.items, { ...product, quantity: 1 }],
})),
removeItem: (id) =>
set((state) => ({
items: state.items.filter((item) => item.id !== id),
})),
clearCart: () => set({ items: [] }),
})
const useStore = create<UserSlice & CartSlice>()((...a) => ({
...createUserSlice(...a),
...createCartSlice(...a),
}))
Use getState and setState for non-reactive access:
const useBearStore = create<BearStore>((set, get) => ({
bears: 0,
increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
doSomething: () => {
const currentBears = get().bears
console.log(`Current bears: ${currentBears}`)
},
}))
// Outside components
const currentState = useBearStore.getState()
useBearStore.setState({ bears: 10 })
import { create } from 'zustand'
interface CounterStore {
count: number
increment: () => void
decrement: () => void
reset: () => void
}
export const useCounterStore = create<CounterStore>((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
reset: () => set({ count: 0 }),
}))
// Usage
function Counter() {
const { count, increment, decrement, reset } = useCounterStore()
return (
<div>
<h1>Count: {count}</h1>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
<button onClick={reset}>Reset</button>
</div>
)
}
import { create } from 'zustand'
interface CartItem {
id: string
name: string
price: number
quantity: number
}
interface CartStore {
items: CartItem[]
addItem: (product: Omit<CartItem, 'quantity'>) => void
removeItem: (id: string) => void
updateQuantity: (id: string, quantity: number) => void
clearCart: () => void
total: number
}
export const useCartStore = create<CartStore>((set, get) => ({
items: [],
addItem: (product) =>
set((state) => {
const existingItem = state.items.find((item) => item.id === product.id)
if (existingItem) {
return {
items: state.items.map((item) =>
item.id === product.id
? { ...item, quantity: item.quantity + 1 }
: item
),
}
}
return {
items: [...state.items, { ...product, quantity: 1 }],
}
}),
removeItem: (id) =>
set((state) => ({
items: state.items.filter((item) => item.id !== id),
})),
updateQuantity: (id, quantity) =>
set((state) => ({
items: state.items.map((item) =>
item.id === id ? { ...item, quantity } : item
),
})),
clearCart: () => set({ items: [] }),
get total() {
return get().items.reduce(
(sum, item) => sum + item.price * item.quantity,
0
)
},
}))
import { create } from 'zustand'
interface User {
id: string
email: string
name: string
}
interface AuthStore {
user: User | null
token: string | null
isLoading: boolean
error: string | null
login: (email: string, password: string) => Promise<void>
logout: () => void
checkAuth: () => Promise<void>
}
export const useAuthStore = create<AuthStore>((set) => ({
user: null,
token: null,
isLoading: false,
error: null,
login: async (email, password) => {
set({ isLoading: true, error: null })
try {
const response = await fetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password }),
})
if (!response.ok) {
throw new Error('Login failed')
}
const { user, token } = await response.json()
set({ user, token, isLoading: false })
localStorage.setItem('token', token)
} catch (error) {
set({
error: error instanceof Error ? error.message : 'Login failed',
isLoading: false,
})
}
},
logout: () => {
localStorage.removeItem('token')
set({ user: null, token: null })
},
checkAuth: async () => {
const token = localStorage.getItem('token')
if (!token) return
set({ isLoading: true })
try {
const response = await fetch('/api/me', {
headers: { Authorization: `Bearer ${token}` },
})
if (!response.ok) {
throw new Error('Auth check failed')
}
const user = await response.json()
set({ user, token, isLoading: false })
} catch (error) {
localStorage.removeItem('token')
set({ user: null, token: null, isLoading: false })
}
},
}))
Use getters for derived state:
const useStore = create<Store>((set, get) => ({
items: [],
get itemCount() {
return get().items.length
},
get hasItems() {
return get().items.length > 0
},
}))
Handle async operations within actions:
const useStore = create<Store>((set) => ({
data: null,
isLoading: false,
error: null,
fetchData: async () => {
set({ isLoading: true, error: null })
try {
const data = await api.fetchData()
set({ data, isLoading: false })
} catch (error) {
set({ error: error.message, isLoading: false })
}
},
}))
Implement a reset action:
const initialState = {
count: 0,
name: '',
}
const useStore = create<Store>((set) => ({
...initialState,
increment: () => set((state) => ({ count: state.count + 1 })),
setName: (name: string) => set({ name }),
reset: () => set(initialState),
}))
// Bad
const useStore = create((set) => ({
items: [],
addItem: (item) => {
// DON'T mutate state directly
items.push(item)
},
}))
// Good
const useStore = create((set) => ({
items: [],
addItem: (item) =>
set((state) => ({
items: [...state.items, item],
})),
}))
// Bad: Causes re-render on any state change
const store = useStore()
// Good: Select only what you need
const count = useStore((state) => state.count)
// Bad: Selector depends on external value
const [userId, setUserId] = useState('123')
const user = useStore((state) => state.users[userId])
// Good: Pass external values as arguments
const getUser = (userId: string) => useStore.getState().users[userId]
// Bad: Splitting related state across stores
const useUserStore = create(...)
const useUserSettingsStore = create(...)
const useUserPreferencesStore = create(...)
// Good: Keep related state together
const useUserStore = create((set) => ({
profile: null,
settings: {},
preferences: {},
}))
Handles the full Supabase workflow from schema changes to deployment, with built-in security guardrails that catch common traps like RLS...
Comprehensive guides and best practices for Neon Serverless Postgres, covering setup, connection methods, authentication, and platform APIs.
Guide for setting up and using Firebase Authentication. Use this skill when the user's app requires user sign-in, user management, or secure data access using auth rules.
A skill to evaluate how secure Firestore security rules are. Use this when Firestore security rules are updated to ensure that the generated rules are extremely secure and robust.
Official skill for integrating Firebase AI Logic (Gemini API) into web applications. Covers setup, multimodal inference, structured output, and security.
Complete Better Auth server and client setup with database adapters, session management, plugins, and security configuration.
Deploy and manage projects on Vercel using token-based authentication. Use when working with Vercel CLI using access tokens rather than interactive login — e.g. "deploy to vercel", "set up vercel", "add environment variables to vercel".
Complete Cloudflare platform integration with decision trees for compute, storage, AI, networking, security, and infrastructure-as-code.
Run Azure compliance and security audits with azqr plus Key Vault expiration checks. Covers best-practice assessment, resource review, policy/compliance validation, and security posture checks. WHEN: compliance scan, security audit, BEFORE running azqr (compliance cli tool), Azure best practices, Key Vault expiration check, expired certificates, expiring secrets, orphaned resources, compliance assessment.
Send, read, and manage Gmail messages, drafts, labels, and account settings.
Comprehensive website auditing across 230+ rules in 21 categories including SEO, performance, security, and accessibility.
Shared authentication, CLI syntax, and output formatting patterns for gws Google Workspace commands.
Discover your celebrity doppelgänger with StarByFace!
GeoSpy: Pricing, Features, FAQs, and Alternatives for AI Teams
Detect AI-generated voices to protect against audio fraud.
Ensure Your Content's Originality with AI Plagiarism Checker
Upscale images by 400% without quality loss
Protect your social media from copyright disputes
Accurately Detect AI-Generated Content with TheChecker.AI
Chrome extension that detects and flags AI-generated content