AgentSkillsCN

react-nextjs

LMS 项目中 React 19 和 Next.js 15 App Router 的开发模式。提供 Server/Client Component 分离、Convex Hook 模式,以及结合 React Hook Form + Zod + shadcn/ui 的表单处理方案。当您在 src/app/**/*.tsx 或 src/components/**/*.tsx 文件中进行开发,或在创建页面、组件、表单时,又或是需要运用 React、Next.js、Server Component、Client Component、Page、Layout、Form 等模式时,可使用此技能。

SKILL.md
--- frontmatter
name: react-nextjs
description: React 19 and Next.js 15 App Router patterns for the LMS project. Provides Server/Client Component separation, Convex hooks patterns, and form handling with React Hook Form + Zod + shadcn/ui. Use when working on files in src/app/**/*.tsx or src/components/**/*.tsx, when creating pages, components, or forms, or when React, Next.js, Server Component, Client Component, page, layout, or form patterns are needed.

React & Next.js Patterns

Stack

  • Next.js 15.5.7, React 19.2.1, TypeScript 5.x (strict)
  • React Hook Form ^7.68.0, Zod ^4.1.13, Convex ^1

Quick Start

Page Pattern (Server Component)

tsx
// src/app/(dashboard)/[feature]/page.tsx
import { auth } from "@clerk/nextjs/server";
import { redirect } from "next/navigation";
import { FeatureView } from "./feature-view";

export default async function FeaturePage() {
  const { userId } = await auth();
  if (!userId) redirect("/sign-in");
  return <FeatureView />;
}

View Pattern (Client Component)

tsx
// src/app/(dashboard)/[feature]/feature-view.tsx
"use client";

import { useQuery } from "convex/react";
import { api } from "@/convex/_generated/api";
import { Skeleton } from "@/components/ui/skeleton";

export function FeatureView() {
  const data = useQuery(api.feature.list);
  if (data === undefined) return <Skeleton className="h-32 w-full" />;
  return (/* JSX */);
}

Validator Pattern

typescript
// src/lib/validators/[domain].ts
import { z } from "zod";

export const createItemSchema = z.object({
  name: z.string().min(2, "Name must be at least 2 characters"),
  email: z.string().email("Invalid email address"),
});

export type CreateItemInput = z.infer<typeof createItemSchema>;

Decision Trees

Server vs Client Component?

code
Need hooks, events, or browser APIs?
├─ YES → Client Component ("use client")
│   └─ Examples: useQuery, useState, onClick, useEffect
└─ NO → Server Component (default)
    └─ Examples: data fetching, auth checks, static content

When to add "use client"?

code
File uses ANY of these?
├─ React hooks (useState, useEffect, useCallback, useMemo)
├─ Convex hooks (useQuery, useMutation, useAction)
├─ Event handlers (onClick, onChange, onSubmit)
├─ Browser APIs (localStorage, window, document)
└─ YES to any → Add "use client" at line 1

useCallback/useMemo in React 19?

code
React 19 compiler auto-memoizes. Manual memoization needed only when:
├─ Passing callback to native element with expensive re-render → useCallback
├─ Computing value used in dependency array → useMemo
├─ Complex computation (>1ms) on every render → useMemo
└─ Otherwise → Skip memoization, let compiler handle it

Strict Rules

ContextRule
PagesServer Components only. Use async function, no hooks. Auth check + redirect + render View.
ViewsClient Components. "use client", hooks, event handlers. Named export FeatureView.
Loadingdata === undefined → render <Skeleton />
ErrorsUse toast.error() from sonner. Never alert() or console.error() for user feedback.
Formsshadcn Form + zodResolver. See references/forms.md.
MutationsuseMutation + toast.success()/toast.error() in try/catch.

Project Conventions

CategoryConvention
Imports@/components/, @/hooks/, @/lib/ aliases
Validatorssrc/lib/validators/[domain].ts
Typesz.infer<typeof schema> (never manual interfaces for form data)
IconsLucide React only
Toastsonner only
UI@/components/ui/* primitives. Never create new UI primitives.
Classnamescn() from @/lib/utils for conditional classes

References

Load these as needed for detailed patterns: