بنقرة واحدة
frontend
Frontend development rules and patterns for Next.js/React projects
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Frontend development rules and patterns for Next.js/React projects
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
| name | frontend |
| description | Frontend development rules and patterns for Next.js/React projects |
components/components/ui/components/[feature]/Dialog → Integrated → Form:
FooDialog.tsx - Dialog wrapper with trigger buttonFooIntegrated.tsx - Form logic + submission handlingFooForm.tsx - Pure form with react-hook-form + zod validationhooks/cn helper for conditional and dynamic classname concatenationconst formatPrice = (price: number) =>
new Intl.NumberFormat("en-NG", {
style: "currency",
currency: "NGN",
maximumFractionDigits: 0,
}).format(price);
Returns: "₦1,500"
// Query
const data = useQuery(api.myFunction, { arg });
// Mutation
const mutate = useMutation(api.myMutation);
mutate({ arg });
import { useForm } from "react-hook-form";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
const schema = z.object({
name: z.string().min(1, "Required"),
});
const { register, handleSubmit } = useForm({
resolver: zodResolver(schema),
});
AlertDialog for destructive actionsDialog for formsTabs, TabsList, TabsTrigger, TabsContentInstead of repeated find() calls in JSX:
// Bad - repeated find in JSX
<Form initialData={currentPlanId ? plans.find(p => p.id === currentPlanId) : undefined} />
// Good - extract to variable
const currentPlan = plans.find(p => p.id === currentPlanId);
<Form initialData={currentPlan} />
const computed = React.useMemo(() => expensiveOperation(data), [data]);
Return early to reduce nesting:
if (!data) return <Skeleton />;
return ( /* main content */ );
Avoid creating separate state for derived values:
// Bad - duplicate state
const [filtered, setFiltered] = useState(data);
useEffect(() => setFiltered(data.filter(...)), [data]);
// Good - derive in render
const filtered = data.filter(...);
// Bad
<Component a={obj.a} b={obj.b} c={obj.c} d={obj.d} />
// Good
const { a, b, c, d } = obj;
<Component a={a} b={b} c={c} d={d} />
// Or as spread
<Component {...pick(obj, 'a', 'b', 'c', 'd')} />
Forms should use local isSubmitting state passed to isLoading prop:
const [isSubmitting, setIsSubmitting] = useState(false);
<Form
isLoading={isSubmitting}
onSubmit={async (values) => {
setIsSubmitting(true);
try {
await mutation(values);
} finally {
setIsSubmitting(false);
}
}}
/>
// Form button shows "Saving..." when isLoading=true
Inline functions cause child components to rerender on every parent render:
// Bad - creates new function each render
<Button onClick={() => handleClick(id)} />
// Good - use stable handler, pass id as argument
<Button onClick={handleClick} payload={id} />
Prefer map with direct access over multiple/nested ternary operations for JavaScript conditionals.
// Bad - nested ternaries
const value = var === "a" ? 1 : var === "b" ? 2 : var === "c" ? 3 : "default";
// Good - map lookup
const valueMap = {
"a": 1,
"b": 2,
"c": 3
};
const value = valueMap[var] || "default";
// Show/Hide with && (for no else case)
{isOpen && <Content />}
// Ternary for else case
{isOpen ? <OpenState /> : <ClosedState />}
Group related components for cleaner exports:
// Instead of
export { Button } from "./button";
export { ButtonGroup } from "./button-group";
// Use compound component
export const Button = Object.assign(ButtonRoot, { Group: ButtonGroup });
// Usage: <Button.Group>