开发教程
组件开发
学习如何在 Codofly Template 中创建和管理 React 组件
组件开发
本文档将指导您如何在 Codofly Template 中创建、管理和复用 React 组件。
组件目录结构
组件组织方式
components/
├── ui/ # 基础 UI 组件 (shadcn/ui)
│ ├── button.tsx # 按钮组件
│ ├── input.tsx # 输入框组件
│ └── card.tsx # 卡片组件
├── auth/ # 认证相关组件
│ ├── login-form.tsx # 登录表单
│ └── signup-form.tsx # 注册表单
├── dashboard/ # 仪表盘组件
│ ├── sidebar.tsx # 侧边栏
│ └── stats-card.tsx # 统计卡片
├── chat/ # 聊天功能组件
│ ├── chat-interface.tsx # 聊天界面
│ └── message-list.tsx # 消息列表
└── shared/ # 共享组件
├── navbar.tsx # 导航栏
├── footer.tsx # 页脚
└── loading.tsx # 加载指示器
UI 组件 (shadcn/ui)
安装新组件
npx shadcn-ui@latest add button
npx shadcn-ui@latest add card
npx shadcn-ui@latest add input
基础使用示例
import { Button } from "@/components/ui/button"
export function ExampleButton() {
return (
<div className="space-x-2">
<Button variant="default">默认按钮</Button>
<Button variant="outline">边框按钮</Button>
<Button variant="destructive">危险按钮</Button>
</div>
)
}
业务组件开发
认证组件示例
"use client"
import { useState } from "react"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
interface LoginFormProps {
onSubmit?: (email: string, password: string) => void
className?: string
}
export function LoginForm({ onSubmit, className }: LoginFormProps) {
const [email, setEmail] = useState("")
const [password, setPassword] = useState("")
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault()
onSubmit?.(email, password)
}
return (
<Card className={className}>
<CardHeader>
<CardTitle>登录</CardTitle>
</CardHeader>
<CardContent>
<form onSubmit={handleSubmit} className="space-y-4">
<Input
type="email"
placeholder="邮箱"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<Input
type="password"
placeholder="密码"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<Button type="submit" className="w-full">
登录
</Button>
</form>
</CardContent>
</Card>
)
}
TypeScript 类型定义
基础组件类型
title="types/components.ts"
import { ReactNode } from "react"
import { LucideIcon } from "lucide-react"
// 基础组件 Props
export interface BaseComponentProps {
className?: string
children?: ReactNode
}
// 表单组件类型
export interface FormFieldProps {
label: string
name: string
type?: "text" | "email" | "password"
placeholder?: string
required?: boolean
value: string
onChange: (value: string) => void
}
// 导航项类型
export interface NavigationItem {
label: string
href: string
icon?: LucideIcon
children?: NavigationItem[]
}
业务数据类型
title="types/business.ts"
// 用户类型
export interface User {
id: string
email: string
name: string
avatar?: string
role: "admin" | "user"
}
// 聊天消息类型
export interface ChatMessage {
id: string
content: string
role: "user" | "assistant"
timestamp: Date
}
// API 响应类型
export interface ApiResponse<T = any> {
success: boolean
data?: T
error?: string
}
样式处理
Tailwind CSS 使用
title="components/styled-example.tsx"
import { cn } from "@/lib/utils"
interface StyledCardProps {
variant?: "default" | "outlined"
className?: string
children: React.ReactNode
}
export function StyledCard({ variant = "default", className, children }: StyledCardProps) {
return (
<div
className={cn(
// 基础样式
"rounded-lg p-6",
// 变体样式
variant === "default" && "bg-card border shadow-sm",
variant === "outlined" && "border-2 border-border",
// 外部样式
className
)}
>
{children}
</div>
)
}
响应式和深色模式
title="components/responsive-example.tsx"
export function ResponsiveComponent() {
return (
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
<div className="bg-white dark:bg-gray-900 p-4 rounded-lg">
<h2 className="text-gray-900 dark:text-white">
支持深色模式的内容
</h2>
</div>
</div>
)
}
组件复用策略
1. 组合组件
title="components/form/index.tsx"
// 表单容器
export function Form({ children, onSubmit }: FormProps) {
return <form onSubmit={onSubmit}>{children}</form>
}
// 表单字段
export function FormField({ label, children }: FormFieldProps) {
return (
<div className="space-y-2">
<label className="text-sm font-medium">{label}</label>
{children}
</div>
)
}
// 使用示例
export function ContactForm() {
return (
<Form onSubmit={handleSubmit}>
<FormField label="姓名">
<Input placeholder="请输入姓名" />
</FormField>
<FormField label="邮箱">
<Input type="email" placeholder="请输入邮箱" />
</FormField>
<Button type="submit">提交</Button>
</Form>
)
}
2. 自定义 Hook
title="hooks/use-form.ts"
import { useState } from "react"
export function useForm<T>(initialValues: T) {
const [values, setValues] = useState(initialValues)
const [errors, setErrors] = useState<Partial<T>>({})
const setValue = (name: keyof T, value: any) => {
setValues(prev => ({ ...prev, [name]: value }))
}
const reset = () => {
setValues(initialValues)
setErrors({})
}
return { values, errors, setValue, reset }
}
3. 高阶组件
title="components/hoc/with-loading.tsx"
import { ComponentType } from "react"
export function withLoading<T extends object>(
Component: ComponentType<T>
) {
return function LoadingComponent(props: T & { loading?: boolean }) {
const { loading, ...rest } = props
if (loading) {
return <div>加载中...</div>
}
return <Component {...(rest as T)} />
}
}
最佳实践
1. 组件命名
- 使用 PascalCase 命名组件
- 文件名与组件名保持一致
- 使用描述性的名称
2. Props 设计
// ✅ 好的做法
interface ButtonProps {
variant?: "primary" | "secondary"
size?: "sm" | "md" | "lg"
disabled?: boolean
children: React.ReactNode
}
// ❌ 避免的做法
interface ButtonProps {
type?: string // 太模糊
data?: any // 类型不明确
}
3. 性能优化
import { memo, useMemo } from "react"
// 使用 memo 避免不必要的重渲染
export const ExpensiveComponent = memo(({ data }: Props) => {
const processedData = useMemo(() => {
return data.map(item => /* 复杂计算 */)
}, [data])
return <div>{/* 渲染内容 */}</div>
})
总结
在 Codofly Template 中开发组件时:
- 使用 shadcn/ui 作为基础 UI 组件
- 按功能模块组织组件目录
- 使用 TypeScript 确保类型安全
- 利用 Tailwind CSS 进行样式设计
- 通过组合和复用提高开发效率
掌握这些概念后,您就能高效地创建和管理组件了。
Assistant
Responses are generated using AI and may contain mistakes.