بنقرة واحدة
ghcopilot-hub-zustand
Zustand 5 state management patterns. Trigger: When managing React state with Zustand.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Zustand 5 state management patterns. Trigger: When managing React state with Zustand.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
Next.js 16 App Router patterns for Server Components, Server Actions, route handlers, caching, streaming, and version-sensitive request APIs. Trigger: Use when working in Next.js 16 App Router code with app/, layout.tsx, page.tsx, loading.tsx, generateMetadata, Server Actions, route.ts handlers, revalidatePath/revalidateTag, cookies()/headers()/params async APIs, middleware.ts vs proxy.ts naming, or RSC streaming and serialization issues.
Next.js best practices - file conventions, RSC boundaries, data patterns, async APIs, metadata, error handling, route handlers, image/font optimization, bundling
React 19 patterns with Compiler-aware guidance, composition, refs, and effects. Trigger: When working with React components (.tsx, .jsx), effects, refs, context APIs, or render performance/memoization decisions.
Layer-aware testing strategies for Clean Architecture using Vitest, React Testing Library, MSW, and Cypress. Use when creating or reviewing unit, integration, component, architectural, or E2E test plans across `src/domain`, `src/application`, `src/infrastructure`, `src/interface`, and `src/presentation`, especially for mocking-boundary decisions, async reliability, and flaky-test prevention. Trigger keywords: test, vitest, cypress, e2e, mock, msw, renderHook, loader, query, router, zustand.
React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.
Advanced TypeScript decision patterns for strict typing: satisfies vs type annotations, exhaustiveness checks, const-derived unions, and performance-aware control/data flow. Trigger: Use when the task involves TypeScript modeling decisions (type vs interface, enum alternatives), strict mode/type errors, generics, utility types, or hot-path performance issues in branching/looping.
| name | ghcopilot-hub-zustand |
| description | Zustand 5 state management patterns. Trigger: When managing React state with Zustand. |
| license | Apache-2.0 |
| metadata | {"author":"jmgomezdev","version":"1.0"} |
import { create } from "zustand";
interface CounterStore {
count: number;
increment: () => void;
decrement: () => void;
reset: () => void;
}
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 } = useCounterStore();
return (
<div>
<span>{count}</span>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
</div>
);
}
import { create } from "zustand";
import { persist } from "zustand/middleware";
interface SettingsStore {
theme: "light" | "dark";
language: string;
setTheme: (theme: "light" | "dark") => void;
setLanguage: (language: string) => void;
}
const useSettingsStore = create<SettingsStore>()(
persist(
(set) => ({
theme: "light",
language: "en",
setTheme: (theme) => set({ theme }),
setLanguage: (language) => set({ language }),
}),
{
name: "settings-storage", // localStorage key
}
)
);
// ✅ Select specific fields to prevent unnecessary re-renders
function UserName() {
const name = useUserStore((state) => state.name);
return <span>{name}</span>;
}
// ✅ For multiple fields, use useShallow
import { useShallow } from "zustand/react/shallow";
function UserInfo() {
const { name, email } = useUserStore(
useShallow((state) => ({ name: state.name, email: state.email }))
);
return <div>{name} - {email}</div>;
}
// ❌ AVOID: Selecting entire store (causes re-render on any change)
const store = useUserStore(); // Re-renders on ANY state change
interface UserStore {
user: User | null;
loading: boolean;
error: string | null;
fetchUser: (id: string) => Promise<void>;
}
const useUserStore = create<UserStore>((set) => ({
user: null,
loading: false,
error: null,
fetchUser: async (id) => {
set({ loading: true, error: null });
try {
const response = await fetch(`/api/users/${id}`);
const user = await response.json();
set({ user, loading: false });
} catch (error) {
set({ error: "Failed to fetch user", loading: false });
}
},
}));
// userSlice.ts
interface UserSlice {
user: User | null;
setUser: (user: User) => void;
clearUser: () => void;
}
const createUserSlice = (set): UserSlice => ({
user: null,
setUser: (user) => set({ user }),
clearUser: () => set({ user: null }),
});
// cartSlice.ts
interface CartSlice {
items: CartItem[];
addItem: (item: CartItem) => void;
removeItem: (id: string) => void;
}
const createCartSlice = (set): CartSlice => ({
items: [],
addItem: (item) => set((state) => ({ items: [...state.items, item] })),
removeItem: (id) =>
set((state) => ({
items: state.items.filter((i) => i.id !== id),
})),
});
// store.ts
type Store = UserSlice & CartSlice;
const useStore = create<Store>()((...args) => ({
...createUserSlice(...args),
...createCartSlice(...args),
}));
import { create } from "zustand";
import { immer } from "zustand/middleware/immer";
interface TodoStore {
todos: Todo[];
addTodo: (text: string) => void;
toggleTodo: (id: string) => void;
}
const useTodoStore = create<TodoStore>()(
immer((set) => ({
todos: [],
addTodo: (text) =>
set((state) => {
// Mutate directly with Immer!
state.todos.push({ id: crypto.randomUUID(), text, done: false });
}),
toggleTodo: (id) =>
set((state) => {
const todo = state.todos.find((t) => t.id === id);
if (todo) todo.done = !todo.done;
}),
}))
);
import { create } from "zustand";
import { devtools } from "zustand/middleware";
const useStore = create<Store>()(
devtools(
(set) => ({
// store definition
}),
{ name: "MyStore" } // Name in Redux DevTools
)
);
// Access store outside components
const { count, increment } = useCounterStore.getState();
increment();
// Subscribe to changes
const unsubscribe = useCounterStore.subscribe((state) =>
console.log("Count changed:", state.count)
);
Use getState() to access the store outside React, for example inside a loader.
// preferences.store.ts
import { create } from 'zustand';
type PreferencesState = {
storeId: string | null;
setStoreId: (id: string) => void;
};
export const usePreferencesStore = create<PreferencesState>((set) => ({
storeId: null,
setStoreId: (id) => set({ storeId: id }),
}));
// route loader
import { redirect } from '@tanstack/react-router';
import { productQueries } from '@/application/product/product.queries';
loader: async ({ context: { queryClient } }) => {
const storeId = usePreferencesStore.getState().storeId;
if (!storeId) {
throw redirect({ to: '/select-store' });
}
await queryClient.ensureQueryData(productQueries.listByStore(storeId));
},
const { count, increment } = useStore(); // Re-renders on ANY state change
// ❌ FORBIDDEN: Storing server state
const useStore = create((set) => ({
users: [], // Use TanStack Query instead
fetchUsers: async () => { ... },
}));
// ❌ FORBIDDEN: Using deprecated shallow import
import { shallow } from 'zustand/shallow'; // Use useShallow from zustand/react/shallow
zustand, state management, react, store, persist, middleware