我用AI把重复的React组件自动生成,结果省下了两天工期

0 阅读1分钟

我用AI把重复的React组件自动生成,结果省下了两天工期

上个月接了个后台管理系统的活,需求里光表格就有12个。每个表格列的字段不一样、操作按钮不同、筛选条件各异,但底层逻辑——数据请求、分页、loading态、空态——一模一样。

第一个我手写了3小时。写到第五个的时候,我已经进入了一种麻木的复制粘贴改字段的机器人状态。写到第八个,我看了眼项目排期,还有两天就要交付。

这时候我开始想:这些组件的差异在哪里,共性又在哪里? 如果能把90%的共性代码交给AI,我只改那10%的不同,是不是有救?

答案是:能。而且我不仅赶上了ddl,还多出来半天重构了旧代码。


整体思路:先抽象,再生成

核心就三步:

  1. 把重复逻辑抽象成模板 — 参数化组件,提取变化点(列定义、API端点、筛选字段)
  2. 写一个AI Prompt模板 — 告诉AI这个组件的结构和变化维度,每次只需输入差异
  3. 批量生成 — 一次性扔给AI,一次拿到12个文件

关键点在于:不要直接让AI凭空写,你得先教会它你的模式。


具体操作步骤

第一步:先手写一个「母版组件」

我挑了一个最典型的表格,把变化的部分都抽成 props 和配置对象。简化后大概这样:

interface TableConfig<T> {
  columns: ColumnType<T>[]
  apiEndpoint: string
  searchFields?: string[]
  rowActions?: (row: T) => ReactNode[]
}

function GenericTable<T>({ config }: { config: TableConfig<T> }) {
  const [data, setData] = useState<T[]>([])
  const [loading, setLoading] = useState(false)
  const [page, setPage] = useState(1)

  useEffect(() => {
    setLoading(true)
    fetch(`${config.apiEndpoint}?page=${page}`)
      .then(res => res.json())
      .then(res => setData(res.list))
      .finally(() => setLoading(false))
  }, [page, config.apiEndpoint])

  if (loading) return <Spin />
  if (data.length === 0) return <Empty />

  return (
    <Table columns={config.columns} dataSource={data} />
  )
}

第二步:写Prompt模板

关键是把你的「模式」喂给 AI。我用的 prompt 长这样:

你是一个React高级开发。下面是一个通用表格组件的使用模式:

<GenericTable
  config={{
    apiEndpoint: string,
    columns: ColumnType[],
    searchFields: string[],
    rowActions: (row) => []
  }}
/>

现在请根据以下需求生成完整代码文件:
- 模块名:用户管理
- API端点:/api/users
- 列:用户名、邮箱、手机号、注册时间、状态(启用/禁用)
- 搜索字段:用户名、邮箱
- 行操作:编辑、禁用/启用切换
- 额外需求:状态列用Tag组件展示颜色区分

输出一个可直接运行的tsx文件。

第三步:批量丢给Claude

我把12个模块的差异写成一张表,一次发给AI:

帮我用上述模板生成以下12个表格模块,每个输出一个tsx文件:

1. 用户管理  | /api/users     | 用户名/邮箱/手机号/注册时间/状态 | 搜索:用户名,邮箱
2. 订单管理  | /api/orders    | 订单号/用户/金额/状态/创建时间   | 搜索:订单号
3. 商品管理  | /api/products  | 商品名/分类/价格/库存/状态       | 搜索:商品名,分类
...

大概3分钟,AI把12个文件全部输出。我逐个检查、微调,总共花了不到2小时。


代码对比:手写 vs AI生成

手写一个表格组件(约120行):

function OrderTable() {
  const [loading, setLoading] = useState(true)
  const [data, setData] = useState([])
  const [page, setPage] = useState(1)
  const [total, setTotal] = useState(0)

  useEffect(() => {
    fetch(`/api/orders?page=${page}&pageSize=20`)
      .then(r => r.json())
      .then(r => { setData(r.list); setTotal(r.total) })
      .finally(() => setLoading(false))
  }, [page])

  const columns = [
    { title: '订单号', dataIndex: 'orderNo' },
    { title: '用户', dataIndex: 'username' },
    { title: '金额', dataIndex: 'amount', render: v => ${v}` },
    { title: '状态', dataIndex: 'status' },
  ]

  return (
    <Table
      loading={loading}
      dataSource={data}
      columns={columns}
      pagination={{ current: page, total, onChange: setPage }}
    />
  )
}

AI基于模板生成(约40行差异代码):

function OrderTable() {
  return (
    <GenericTable
      config={{
        apiEndpoint: '/api/orders',
        columns: [
          { title: '订单号', dataIndex: 'orderNo' },
          { title: '用户', dataIndex: 'username' },
          { title: '金额', dataIndex: 'amount', render: v => `¥${v}` },
          { title: '状态', dataIndex: 'status' },
        ],
        searchFields: ['orderNo'],
      }}
    />
  )
}

12个表格,从近1500行手写代码,降到约500行(其中大部分是列定义这种真正有业务价值的代码)。


踩坑点

1. AI不会自动替你「最佳实践」

第一次生成时,AI把 GenericTable 写成了 any 大法,类型安全全丢了。解决方案:在母版组件里就把 TypeScript 泛型写好,在 prompt 里明确要求「保留完整类型」

2. 模板不能太灵活,也不能太死

一开始我把模板搞得太抽象,期望 AI 能处理各种边界情况。结果 AI 生成出来的代码总有一些奇怪的兼容处理,导致运行时暴错。后来我只提取95%场景下的共同模式,剩下5%的差异化直接写在各组件里覆写。

3. AI会「忘记」你的命名规范

给12个文件命名,AI最后除了两个 index.tsx,还有叫 UserListPage.tsxuser-table.tsxuserManagement.tsx 的。一定要在 prompt 里强调文件命名规范

4. 别让AI一口气生成太多

试过一次让它生成20个,结果到第15个就开始掉 token 质量下降。建议每批5-8个,分批生成,质量可控。


总结

这次之后我自己的工作流变成了这样:

  1. 人工 — 手写1个母版组件(1-2小时)
  2. AI — 批量生成N个变体(几分钟)
  3. 人工 — 逐个review + 跑测试(半小时-1小时)

整体效率至少提升了3-4倍。而且心态完全变了——以前看到重复组件就头大,现在反而有点期待:又能练一次 Prompt 技巧了 🎯

给一个可执行的建议:

下次接到重复组件多的需求,别急着敲键盘。先花15分钟想清楚「哪些是共性,哪些是差异」,写一个配置驱动的基础组件,然后给AI喂一个带示例的 prompt。你只需要把那15%真正有业务逻辑差异的部分写好,剩下的交给 AI 去填空。

这玩意儿不神秘,就是个「把费时的重复劳动外包出去」的思路。AI是你的实习生,你是那个把关的 senior —— 听起来是不是舒服多了?