antd 原有的 Form 组件其实已经足够好用了,但是这次 4.0 对 Form 的更新开始注重不止要好用,还要“优雅”。“优雅”这个东西一直都很玄学。
antd 的 Form 一直以来都很特例独行,区别于其它 antd 组件,Form 的调用并不只是简单的引入组件即可,而是先要进行 Form.create()创建一个 Form 实例,使用 FormItem 时还需在 jsx 中调用 form.getFieldDecorator 方法,写法较为复杂,况且在 jsx 中插入大量的非节点代码,造成代码结构复杂,且一般情况下,一个 Form 表单会有多个 FormItem,也就意味着我们需要重复的去调用 form.getFieldDecorator 方法,导致后期维护成本很高。写这种重复且简单的无意义的代码,这和开篇所说的“优雅”背道而驰。
为了解决这些问题,这次 antd 团队从底层重写了 Form。首先,去掉了 Form.create()这一步操作,改为直接在组件内部去完成。另外将原来的 FormItem 的调用方式也进行了优化,下面是老版本的 FormItem 的调用示例:
<FormItem {...formItemLayout} label="姓名">
{form.getFieldDecorator("name", {
rules: [
{
required: true,
message: "姓名不能为空",
},
],
initialValue: data.name,
})(<Input placeholder="请输入姓名" />)}
</FormItem>
可以看到,老版本实际上是在组件的 jsx 中调用了 form.getFieldDecorator 方法,本质上是一个高阶组件,然后再将 FormItem 的组件作为参数传入,先不说这种方式复杂与否。如果这个表单有多个 FormItem,这段代码将变得异常混乱。而在 antd 4.0 中,官方也意识到了这个问题,下面是一个新版本 Form 的调用示例:
<Form
layout="vertical"
initialValues={{
name: data.name,
}}
onFinish={this.onSubmit}
>
<Form.Item
label="姓名"
name="name"
rules={[
{
required: true,
message: "姓名不能为空",
},
]}
>
<Input placeholder="请输入姓名" />
</Form.Item>
</Form>
可以看到,FormItem 的调用方式更加纯粹了,更像是一个组件的调用,无需再写冗杂的函数调用代码,这样即使是数据了也能保证代码整洁,降低后期维护成本。表单输入完成后,直接使用 Form 的 onFinish 方法,便可以拿到验证通过之后的数据。弃用了之前的先调用 form.validateFields,然后判断是否验证通过,然后再通过回调拿到验证通过之后的值。又向更加便捷迈进了一步。
同时本次也引入了 ref 句柄,可以通过 ref 来主动调用 validateFields 事件,比如说像这样子:
this.formRef.current
.validateFields()
.then((values) => {
// do somethings
})
.catch((errors) => {
// do somethings
});
看着这长长的一行代码,你想到了什么?对!就是 jQuery。这种写法真的太像 jQuery 的链式调用啦~让我有一种回到了 DOM 操作的时代,这种方式十分容易理解:先通过 ref 句柄拿到 Form 实例,然后调用它的 validateFields 方法,然后如果校验通过做什么,校验失败又要做什么,十分的语义化,一目了然,代码逻辑一下子就明白了。
最后,官方说了,后期可能会推出跟 ProTable 类似的 ProForm,将基础表单直接封装起来,常用的基础表单直接配置数据即可使用,后期修改也只用维护这份配置数据,做到真正的数据驱动。期待中....