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,来将表单与列表分开到不同的页面。

相关推荐
lumi.3 分钟前
Vue.js 从入门到实践1:环境搭建、数据绑定与条件渲染
前端·javascript·vue.js
二十雨辰4 分钟前
vue核心原理实现
前端·javascript·vue.js
影子信息7 分钟前
[Vue warn]: Error in mounted hook: “ReferenceError: Jessibuca is not defined“
前端·javascript·vue.js
卷Java38 分钟前
CSS模板语法修复总结
java·前端·css·数据库·微信小程序·uni-app·springboot
gihigo19981 小时前
在CentOS上配置SVN至Web目录的自动同步
前端·svn·centos
珍宝商店1 小时前
优雅的 async/await 错误处理模式指南
开发语言·前端·javascript
excel2 小时前
楖览:Vue3 源码研究导读
前端
proud12122 小时前
开源的 CSS 动画库
前端·css·开源
折翼的恶魔2 小时前
HTML媒体标签
前端·html
excel2 小时前
前端项目中的测试分类与实践 —— 以 Vue 项目为例
前端