React 规范
核心原则
React 组件必须使用函数式组件和 Hooks,遵循 React 19 最佳实践,确保组件的可复用性。
允许的做法
组件定义
- 使用 函数式组件
- 使用 TypeScript 定义 Props
tsx
// ✅ 正确
import { cn } from '@/lib/utils';
interface UserCardProps {
user: User;
onEdit?: (id: number) => void;
className?: string;
}
function UserCard({ user, onEdit, className }: UserCardProps) {
return (
<div className={cn('rounded-lg border bg-card p-4', className)}>
<h3 className="text-lg font-semibold">{user.name}</h3>
<button
className="mt-2 px-4 py-2 bg-primary text-primary-foreground rounded-md"
onClick={() => onEdit?.(user.id)}
>
编辑
</button>
</div>
);
}
export default UserCard;Hooks 使用
tsx
// ✅ 正确
function UserList() {
const [users, setUsers] = useState<User[]>([]);
const [loading, setLoading] = useState(false);
useEffect(() => {
loadUsers();
}, []);
const loadUsers = async () => {
setLoading(true);
const data = await userService.getList();
setUsers(data);
setLoading(false);
};
if (loading) {
return <div className="flex justify-center py-8">加载中...</div>;
}
return <div className="space-y-4">{/* 渲染 */}</div>;
}条件渲染
tsx
// ✅ 正确
function UserProfile({ user }: { user?: User }) {
if (!user) {
return (
<div className="text-center text-muted-foreground py-8">
用户不存在
</div>
);
}
return (
<div className="space-y-2">
<h1 className="text-2xl font-bold">{user.name}</h1>
{user.isVip && (
<span className="inline-flex items-center px-2 py-1 rounded-full text-xs bg-primary text-primary-foreground">
VIP
</span>
)}
</div>
);
}列表渲染
tsx
// ✅ 正确
function UserList({ users }: { users: User[] }) {
return (
<ul className="space-y-2">
{users.map(user => (
<li key={user.id}>
<UserCard user={user} />
</li>
))}
</ul>
);
}自定义 Hooks
tsx
// ✅ 正确
function useUser(id: number) {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
setLoading(true);
setError(null);
userService.getById(id)
.then(setUser)
.catch((e) => setError(e.message))
.finally(() => setLoading(false));
}, [id]);
return { user, loading, error };
}禁止的做法
- 禁止 使用 Class 组件
- 禁止 在条件/循环中调用 Hooks
tsx
// ❌ 错误
class UserCard extends React.Component {}
function BadComponent() {
if (condition) {
useState(0); // 禁止
}
}性能优化
tsx
// ✅ 正确 - 使用 memo
const UserCard = React.memo(({ user }: { user: User }) => {
return <div className="p-4 border rounded-lg">{user.name}</div>;
});
// ✅ 正确 - useMemo
const total = useMemo(
() => products.reduce((sum, p) => sum + p.price, 0),
[products]
);
// ✅ 正确 - useCallback
const handleClick = useCallback((id: number) => {
console.log('clicked', id);
}, []);