optimizer
GitHub指导 NowStack 应用开发的最佳实践,涵盖 Zustand 状态管理、TanStack Router URL 状态、Convex 数据获取及表单处理,优化前端性能与架构。
Trigger Scenarios
Install
npx skills add Melvynx/Parler --skill optimizer -g -y
SKILL.md
Frontmatter
{
"name": "optimizer",
"description": "This skill should be used when the user asks to \"optimize\", \"improve performance\", \"add state management\", \"add URL state\", or mentions Zustand, TanStack Form, client-side fetching with Convex, optimistic updates, or custom async mutation\/query hooks. Provides best practices for state management, URL state via TanStack Router, data fetching with Convex queries, and forms."
}
If the optimization target is Convex database bandwidth, documents read vs
returned, .filter() scans, index design, or expensive Convex query syntax,
use convex-cost-optimizer first.
<quick_start> <decision_tree> Choose the right tool:
| Need | Solution | Reference |
|---|---|---|
| Shared UI state between components | Zustand store | references/state-management.md |
| LocalStorage-persisted state | Zustand with persist middleware |
references/state-management.md |
| URL state (filters, pagination) | TanStack Router search params (useSearch) |
references/client-side-fetch.md |
| Server data on a route | Server guard/loader + Convex useQuery |
references/client-side-fetch.md |
| Live-updating server data | useQuery(api.x.y, args) from convex/react |
references/client-side-fetch.md |
| Convex mutation | useMutation(api.x.y) from convex/react |
references/client-side-fetch.md |
| Non-reactive async read | useAsyncQuery |
references/client-side-fetch.md |
| Imperative async mutation lifecycle | TanStack Query useMutation or useAction |
references/client-side-fetch.md |
| Optimistic mutation | Convex .withOptimisticUpdate(...) |
references/client-side-fetch.md |
| Form handling | TanStack Form | references/forms.md |
</decision_tree>
<zustand_quick>
import { create } from "zustand";
type MyStore = {
value: string;
setValue: (value: string) => void;
};
export const useMyStore = create<MyStore>((set) => ({
value: "",
setValue: (value) => set({ value }),
}));
</zustand_quick>
<convex_query_quick>
import { useQuery } from "convex/react";
import { api } from "@convex/_generated/api";
const subscription = useQuery(
api.subscriptions.queries.getActiveByOrganization,
org.id ? { organizationId: org.id } : "skip",
);
</convex_query_quick>
<tanstack_form_quick>
import { useForm, Form } from "@/features/form/tanstack-form";
const form = useForm({
schema: MySchema,
defaultValues: { field: "" },
onSubmit: async ({ value }) => {
await mutation.mutateAsync(value);
},
});
<Form form={form}>
<form.AppField name="field">{(field) => <field.Input />}</form.AppField>
<form.SubmitButton>Submit</form.SubmitButton>
</Form>;
</tanstack_form_quick> </quick_start>
<core_principles> <zustand_when> Use Zustand when:
- Sharing UI state between multiple components (open/closed dialogs, sidebars, preferences)
- Persisting client-side state to localStorage
- State must be reachable from outside React (e.g.
dialogManager.confirm(...))
Do NOT use Zustand for:
- Server data — use Convex
useQuery/useMutation - URL state — use TanStack Router search params
- Form state — use TanStack Form </zustand_when>
<query_when> Use Convex React hooks when:
- Fetching Convex data from React components
- You want live subscription updates
- Multiple components read the same backend data
- You need Convex optimistic updates
Do NOT use React Query for:
- One-off computed values that don't hit Convex (use
useMemo) - Data that has zero re-render value (compute it inline)
- Convex subscriptions already handled by
convex/react
Use TanStack Query mutations for:
- Imperative form submissions that need
isPending,mutateAsync,onSuccess, oronError - Wrapping Convex mutations/actions when the UI needs lifecycle callbacks </query_when>
<form_when> ALWAYS use TanStack Form for new forms:
- Validates with Zod
- Handles loading states
- Integrates with mutations
- Pre-built field components in
@/features/form/tanstack-form
Legacy: A few existing components still use useZodForm from @/components/ui/form (react-hook-form). Don't propagate that pattern — convert if you touch the file.
</form_when>
</core_principles>
<anti_patterns>
useState for state that lives in multiple components:
// BAD - state duplicated in each component
const [isOpen, setIsOpen] = useState(false);
<reference_guides>
references/client-side-fetch.md— Convex queries, route loaders, search params, optimistic mutationsreferences/state-management.md— Zustand store patterns and persistencereferences/forms.md— TanStack Form patterns, validation, auto-save </reference_guides>
<success_criteria>
- Zustand used for shared UI state, never for server data
- All client-side Convex data is fetched via
useQuery(api.x.y, args)fromconvex/react - TanStack Form used for new forms, with Zod validation
- URL state lives in route search params, not local component state
- Convex mutations rely on reactive subscriptions, with optimistic updates only when the UI needs instant local feedback </success_criteria>
Version History
- 1aaa38b Current 2026-08-20 07:35


