AI 编程时代手工匠人代码打造 React 项目实战 (二):引入组件库 Antd

前置工作

使用 pnpm i antd @ant-design/icons 安装 antd 和它提供的图标库来作为我们项目的 UI 库。

编码流程

1.修改 Table 组件

我们参照 antd 的官方文档,定义一个 columns 来描述每一列。

tsx 复制代码
//App.tsx
const columns = [
  {
    title: '用户ID',
    dataIndex: 'userId',
    key: 'userId',
  },
  {
    title: '姓名',
    dataIndex: 'name',
    key: 'name',
  },
  {
    title: '年龄',
    dataIndex: 'age',
    key: 'age',
  },
  {
    title: '所在地',
    dataIndex: 'city',
    key: 'city',
  },
  {
    title: '角色名称',
    dataIndex: 'role',
    key: 'role',
  },
  {
    title: '操作',
    dataIndex: 'operation',
    key: 'operation',
  },
]
//...
return (
  //...
  <Table columns={columns} dataSource={filterData} />
)

现在 Table 组件已经能够正常显示数据了,下一步我们将原有的操作的按钮和编辑模式加上,查阅文档我们可以发现 Column 提供了一个 render 的接口,用来定义每一列的渲染逻辑,入参形式为(当前单元格的值,当前行数据,行索引) => {} ,我们根据之前的代码逻辑来改写对应的列定义。

tsx 复制代码
//App.tsx
const columns: TableProps<User>["columns"] = [
  {
    title: "姓名",
    dataIndex: "name",
    key: "name",
    render: (_, record) => {
      return (
        <>
          {editMap[record.userId] ? (
            <input
              ref={(node) => {
                const map = getMap();
                map.set(record.userId, node as HTMLInputElement);
                return () => {
                  map.delete(record.userId);
                };
              }}
              value={editMap[record.userId].name}
              onChange={(e) => handleChange(e, record.userId)}
            />
          ) : (
            <span>{record.name}</span>
          )}
        </>
      );
    },
  },
  //...
  {
    title: "操作",
    dataIndex: "operation",
    key: "operation",
    render: (_, record) => {
      return (
        <>
          {editMap[record.userId] ? (
            <button onClick={() => handleConfirmEdit(record.userId)}>
              保存
            </button>
          ) : (
            <button onClick={() => handleEdit(record.userId)}>修改</button>
          )}
          <button onClick={() => handleDelete(record.userId)}>删除</button>
        </>
      );
    },
  },
];
2. 修改 Form 组件

使用 Form 组件的时候,如果是用过 Vue 的同学可能会感觉到有点别扭。一般在 Vue 中我们会定义一个 formData 的响应式对象来收集数据,然后在控件上使用 v-model 来控制控件的值。而查看 Antd 的 Form 组件示例代码,会发现它完全没有在控件上传入 value 或是 onChange 这样的字段,Form 组件内集中管理了表单控件的状态,并且向外暴露 useForm hook 让我们可以获取状态或者操作它们。

tsx 复制代码
// App.tsx
function UserForm({ onAddUser }: { onAddUser: (user: UserFormData) => void }) {
  const [form] = Form.useForm();
​
  const handleReset = () => {
    form.resetFields();
  };
​
  const handleSubmit = async () => {
    // 触发校验
    await form.validateFields()
    // 获取表单的值
    const formData = form.getFieldsValue();
    onAddUser({
      ...formData,
      age: Number(formData.age),
    });
    // 添加之后 reset
    handleReset()
  };
​
  return (
    <>
      <Form
        form={form}
        labelCol={{ span: 8 }}
        wrapperCol={{ span: 16 }}
        style={{ maxWidth: 600 }}
        initialValues={defaultFormData}
        autoComplete="off"
      >
        <Form.Item<UserFormData>
          label="姓名"
          name="name"
          rules={[{ required: true, message: "请输入姓名" }]}
        >
          <Input />
        </Form.Item>
        <Form.Item<UserFormData>
          label="年龄"
          name="age"
          rules={[{ required: true, message: "请输入年龄" }]}
        >
          <Input />
        </Form.Item>
        <Form.Item<UserFormData>
          label="所在地"
          name="city"
          rules={[{ required: true }]}
        >
          <Select>
            <Select.Option value={"深圳"}>深圳</Select.Option>
            <Select.Option value={"广州"}>广州</Select.Option>
          </Select>
        </Form.Item>
        <Form.Item<UserFormData>
          label="角色"
          name="role"
          rules={[{ required: true }]}
        >
          <Select>
            <Select.Option value={"销售"}>销售</Select.Option>
            <Select.Option value={"销售经理"}>销售经理</Select.Option>
          </Select>
        </Form.Item>
​
        <Form.Item label={null}>
          <button type="button" onClick={handleSubmit}>
            添加
          </button>
          <button type="button" onClick={handleReset}>
            重置
          </button>
        </Form.Item>
      </Form>
    </>
  );
}

验证一下代码功能,发现和我们预期的一样。handleSubmit 其实还能够简化, Form 组件会监听 onSubmit ,在校验成功后触发一个名为 onFinished 事件。

tsx 复制代码
// App.tsx
const handleSubmit = (values: UserFormData) => {
  onAddUser({
    ...values,
    age: Number(values.age),
  });
  // 添加之后 reset
  handleReset()
};
//...
<Form
  //...
  onFinish={handleSubmit}
>
  //...
  <Form.Item label={null}>
    // 修改 type 为 submit,触发表单的 submit 事件
    <button type="submit">
      添加
    </button>
    <button type="button" onClick={handleReset}>
      重置
    </button>
  </Form.Item>
</Form>

小结

我们将原生 HTML 标签替换为了常用 UI 库的组件,并且发现了一些它设计理念上与 Vue 实践中的差异,接下来我们将引入 React Router,来将表单与列表分开到不同的页面。

相关推荐
键盘不能没有CV键3 小时前
【图片处理】✈️HTML转图片字体异常处理
前端·javascript·html
yantuguiguziPGJ3 小时前
WPF 联合 Web 开发调试流程梳理(基于 Microsoft.Web.WebView2)
前端·microsoft·wpf
大飞记Python4 小时前
部门管理|“编辑部门”功能实现(Django5零基础Web平台)
前端·数据库·python·django
tsumikistep5 小时前
【前端】前端运行环境的结构
前端
你的人类朋友5 小时前
【Node】认识multer库
前端·javascript·后端
Aitter5 小时前
PDF和Word文件转换为Markdown的技术实现
前端·ai编程
mapbar_front6 小时前
面试问题—上家公司的离职原因
前端·面试
昔人'6 小时前
css使用 :where() 来简化大型 CSS 选择器列表
前端·css
昔人'6 小时前
css `dorp-shadow`
前端·css
流***陌6 小时前
扭蛋机 Roll 福利房小程序前端功能设计:融合趣味互动与福利适配
前端·小程序