react
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseReact
React
Instructions
说明
This project uses React 19 with TypeScript and the React Compiler enabled via .
babel-plugin-react-compiler本项目使用React 19 + TypeScript,并通过启用了React Compiler。
babel-plugin-react-compilerComponent Structure
组件结构
- Pages live in and are rendered via Inertia
resources/js/pages/ - Shared components live in
resources/js/components/ - UI primitives (shadcn/ui) live in
resources/js/components/ui/ - Custom hooks live in
resources/js/hooks/
- 页面文件存放于,通过Inertia进行渲染
resources/js/pages/ - 共享组件存放于
resources/js/components/ - UI基础组件(shadcn/ui)存放于
resources/js/components/ui/ - 自定义Hooks存放于
resources/js/hooks/
Page Props from Controllers
从控制器获取页面Props
Always receive page data as props from the Laravel controller via Inertia. Do NOT fetch data client-side or use to load page data.
<code-snippet name="Controller Passing Props" lang="php">
// In Laravel controller
public function edit(Project $project): Response
{
return Inertia::render('projects/edit', [
'project' => $project->load('client'),
'clients' => Client::orderBy('name')->get(),
]);
}
</code-snippet>
<code-snippet name="Page Receiving Props" lang="tsx">
// In React page component
import { Project, Client } from '@/types';
useEffectinterface EditProjectProps {
project: Project;
clients: Client[];
}
export default function EditProject({ project, clients }: EditProjectProps) {
return (
<Form action={update({ project: project.id }).url} method="patch">
{/* Form fields using project and clients data */}
</Form>
);
}
</code-snippet>
This pattern ensures:
- State consistency - The server is the single source of truth; no client-side caching or stale data issues
- Data is loaded server-side before the page renders
- No loading states needed for initial page data
- SEO-friendly server-rendered content
- Type-safe props matching controller output
始终通过Inertia从Laravel控制器接收页面数据作为Props。不要在客户端获取数据,也不要使用加载页面数据。
<code-snippet name="Controller Passing Props" lang="php">
// In Laravel controller
public function edit(Project $project): Response
{
return Inertia::render('projects/edit', [
'project' => $project->load('client'),
'clients' => Client::orderBy('name')->get(),
]);
}
</code-snippet>
<code-snippet name="Page Receiving Props" lang="tsx">
// In React page component
import { Project, Client } from '@/types';
useEffectinterface EditProjectProps {
project: Project;
clients: Client[];
}
export default function EditProject({ project, clients }: EditProjectProps) {
return (
<Form action={update({ project: project.id }).url} method="patch">
{/* Form fields using project and clients data */}
</Form>
);
}
</code-snippet>
该模式可确保:
- 状态一致性 - 服务器作为单一数据源,不存在客户端缓存或数据过期问题
- 数据在页面渲染前已在服务器端加载完成
- 初始页面数据无需加载状态
- 支持SEO的服务器渲染内容
- 与控制器输出匹配的类型安全Props
TypeScript Conventions
TypeScript规范
- All component props should be typed explicitly
- Use interfaces for object shapes, defined in
resources/js/types/index.d.ts - Prefer for extending native element props
React.ComponentProps<"element"> - Use path aliases: ,
@/components,@/hooks,@/lib@/types
interface CardProps {
title: string;
description?: string;
className?: string;
children: React.ReactNode;
}
export function Card({ title, description, className, children }: CardProps) {
return (
<div className={cn('rounded-lg border p-4', className)}>
<h3 className="font-semibold">{title}</h3>
{description && <p className="text-muted-foreground">{description}</p>}
{children}
</div>
);
}
</code-snippet>
- 所有组件Props都应显式定义类型
- 对象结构使用接口定义,存放于
resources/js/types/index.d.ts - 优先使用扩展原生元素Props
React.ComponentProps<"element"> - 使用路径别名:,
@/components,@/hooks,@/lib@/types
interface CardProps {
title: string;
description?: string;
className?: string;
children: React.ReactNode;
}
export function Card({ title, description, className, children }: CardProps) {
return (
<div className={cn('rounded-lg border p-4', className)}>
<h3 className="font-semibold">{title}</h3>
{description && <p className="text-muted-foreground">{description}</p>}
{children}
</div>
);
}
</code-snippet>
React 19 + React Compiler
React 19 + React Compiler
- The React Compiler automatically memoizes components and hooks
- Do NOT manually add ,
useMemo, oruseCallbackunless profiling shows a specific needReact.memo - Write straightforward code and let the compiler optimize
- React Compiler会自动对组件和Hooks进行记忆化处理
- 除非性能分析显示有特定需求,否则不要手动添加、
useMemo或useCallbackReact.memo - 编写简洁直观的代码,交由编译器进行优化
State Management
状态管理
- Use React's built-in and
useStatefor local stateuseReducer - Use Inertia's shared data for server-provided state (accessed via )
usePage() - For form state, use the Inertia component (see inertia skill)
<Form>
export function UserGreeting() {
const { auth } = usePage<SharedData>().props;
return <span>Hello, {auth.user.name}</span>;}
</code-snippet>
- 本地状态使用React内置的和
useStateuseReducer - 服务器提供的状态使用Inertia的共享数据(通过访问)
usePage() - 表单状态使用Inertia的组件(参考Inertia相关技能)
<Form>
export function UserGreeting() {
const { auth } = usePage<SharedData>().props;
return <span>Hello, {auth.user.name}</span>;}
</code-snippet>
Event Handlers
事件处理
- Use inline arrow functions for simple handlers
- Extract to named functions only when logic is complex or reused
- 简单处理函数使用内联箭头函数
- 仅当逻辑复杂或需要复用时,才提取为命名函数
Conditional Rendering
条件渲染
- Use early returns for guard clauses
- Prefer for simple conditionals, ternaries for if/else
&& - Use separate components for complex conditional logic
return (
<div>
{data.items.length > 0 && <ItemList items={data.items} />}
{data.error ? <ErrorMessage error={data.error} /> : <SuccessIndicator />}
</div>
);}
</code-snippet>
- 使用提前返回实现守卫子句
- 简单条件优先使用,if/else场景使用三元表达式
&& - 复杂条件逻辑使用独立组件实现
return (
<div>
{data.items.length > 0 && <ItemList items={data.items} />}
{data.error ? <ErrorMessage error={data.error} /> : <SuccessIndicator />}
</div>
);}
</code-snippet>
File Naming
文件命名规范
- Components: PascalCase ()
UserCard.tsx - Hooks: camelCase with prefix (
use)useClipboard.ts - Utilities: camelCase ()
formatDate.ts - Pages: kebab-case matching the route (,
edit.tsx,create.tsx)index.tsx
- 组件:大驼峰命名()
UserCard.tsx - Hooks:小驼峰命名并以为前缀(
use)useClipboard.ts - 工具函数:小驼峰命名()
formatDate.ts - 页面:短横线命名,与路由匹配(,
edit.tsx,create.tsx)index.tsx