Skip to content
第 18 章 前端 ⏱ 12 分钟阅读

第 18 章:组件库 ​

学习目标 ​

  • 了解 React 主流组件库及其特点
  • 掌握 shadcn/ui 的安装与使用
  • 用 Tailwind 快速构建自定义组件
  • 避开组件库的 4 个常见坑

一、主流组件库对比 ​

组件库风格大小特点
Material UI (MUI)Material Design大功能最全
Ant Design企业后台大中后台首选
Chakra UI简洁现代中易用
shadcn/ui复制粘贴小可定制
Radix UI无样式小行为/可访问性
Heroicons图标-配合任意库

二、shadcn/ui(2025 推荐) ​

不是传统组件库,而是复制源码到项目里,完全可控:

bash
npx shadcn-ui@latest init
npx shadcn-ui@latest add button card dialog

生成的组件在 src/components/ui/:

tsx
import { Button } from '@/components/ui/button';
import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card';

function Demo() {
  return (
    <Card>
      <CardHeader>
        <CardTitle>标题</CardTitle>
      </CardHeader>
      <CardContent>
        <Button>点击</Button>
      </CardContent>
    </Card>
  );
}

优势:

  • 样式基于 Tailwind + CSS 变量
  • 完全可改源码
  • 暗色模式开箱即用
  • 基于 Radix UI,可访问性优秀

三、MUI(企业级) ​

bash
npm install @mui/material @emotion/react @emotion/styled
tsx
import { Button, TextField, Stack } from '@mui/material';

function Demo() {
  return (
    <Stack spacing={2}>
      <TextField label="用户名" variant="outlined" />
      <Button variant="contained">提交</Button>
    </Stack>
  );
}

四、Ant Design(中后台) ​

bash
npm install antd
tsx
import { Button, Form, Input, Table } from 'antd';

function Demo() {
  return (
    <Form>
      <Form.Item name="username">
        <Input placeholder="用户名" />
      </Form.Item>
      <Button type="primary" htmlType="submit">提交</Button>
    </Form>
  );
}

五、Headless UI(无样式逻辑) ​

适合自己设计样式时使用,提供行为但不带样式:

bash
npm install @headlessui/react
tsx
import { Dialog } from '@headlessui/react';

function Demo() {
  const [open, setOpen] = useState(false);
  return (
    <Dialog open={open} onClose={() => setOpen(false)}>
      <Dialog.Panel>
        <Dialog.Title>标题</Dialog.Title>
        <p>内容</p>
        <button onClick={() => setOpen(false)}>关闭</button>
      </Dialog.Panel>
    </Dialog>
  );
}

六、图标库 ​

bash
npm install lucide-react       # shadcn 默认
# 或
npm install @heroicons/react
# 或
npm install react-icons
tsx
import { Search, Plus, Trash2 } from 'lucide-react';

<button>
  <Plus className="w-4 h-4" /> 新建
</button>

⚠️ 坑 1:按需 import,不要 import * as Icons from 'lucide-react' 然后 <Icons.Search />,打包体积爆炸。

七、表单组件 ​

react-hook-form + zod(组合推荐) ​

tsx
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';

const schema = z.object({
  email: z.string().email('邮箱格式错误'),
  password: z.string().min(6, '至少 6 位'),
});

type FormData = z.infer<typeof schema>;

function LoginForm() {
  const { register, handleSubmit, formState: { errors } } = useForm<FormData>({
    resolver: zodResolver(schema),
  });

  return (
    <form onSubmit={handleSubmit(console.log)}>
      <input {...register('email')} />
      {errors.email && <span>{errors.email.message}</span>}

      <input type="password" {...register('password')} />
      {errors.password && <span>{errors.password.message}</span>}

      <button>提交</button>
    </form>
  );
}

八、数据表格 ​

tsx
import { DataGrid } from '@mui/x-data-grid';

const columns = [
  { field: 'id', headerName: 'ID', width: 90 },
  { field: 'name', headerName: '姓名', width: 150 },
];

< DataGrid rows = { users } columns = { columns } />

或自建(更灵活):

tsx
function DataTable({ rows, columns }: Props) {
  return (
    <table>
      <thead>
        <tr>{columns.map(c => <th key={c.key}>{c.title}</th>)}</tr>
      </thead>
      <tbody>
        {rows.map(row => (
          <tr key={row.id}>
            {columns.map(c => <td key={c.key}>{row[c.key]}</td>)}
          </tr>
        ))}
      </tbody>
    </table>
  );
}

⚠️ 坑 2:大数据表格(>1000 行)用虚拟滚动(@tanstack/react-virtual),否则卡顿。

九、暗色模式 ​

tsx
// next-themes
import { ThemeProvider } from 'next-themes';

<ThemeProvider attribute="class">
  <App />
</ThemeProvider>

// 使用
import { useTheme } from 'next-themes';
const { theme, setTheme } = useTheme();
<button onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}>切换</button>

⚠️ 坑 3:暗色模式一定要防闪烁(FOUC),用 class 属性 + SSR 注入 class。

十、本章小结 ​

要点关键
选型中后台用 Antd/MUI,定制用 shadcn
shadcn复制源码,可控,Tailwind 友好
按需引入不要全量 import 图标/组件
表单react-hook-form + zod 组合
大表格用虚拟滚动
暗色模式next-themes 防闪烁

动手练习 ​

  1. shadcn 初始化:在 Next.js 项目里 init shadcn,加 Button/Card 组件
  2. 登录页:用 shadcn 的 Input + Button + Card 拼一个登录页
  3. 图标使用:在按钮里加 lucide-react 图标,演示 hover 效果
  4. 找坑:以下代码打包后会怎样?
    tsx
    import * as Icons from 'lucide-react';
    <Icons.Search />

下一章:第 19 章:TypeScript + React →

本站基于 VitePress 构建 · 由 StackHub 团队维护