Ant Design4中Form.List和shouldUpdate一起使用的坑

背景

        在antd3.x版本中,如果要实现一组表单增加删除的功能,需要Array.map()加上state状态来控制,代码比较复杂,而且非常不优雅。

        其次在antd3.x中,表单中任何一个表单项的内容更新都会触发页面重新渲染,这在一个巨型表单页面上简直是灾难。(但是这对于表单联动却是非常方便的,只需要在需要联动的表单前加上判断语句即可)

        因此。antd4相对于antd3对表单进行了一些优化,其中就增加了Form.List这个API和shouldUpdate方法。

        其中Form.List为字段提供数组化管理,可用于动态增加删除移动表单项。

        Form.Item上的shouldUpdate方法用来自定义字段的更新逻辑。

        但是其中有一些坑真让人头大

坑1:同时联动多个表单,样式问题

        首先,antd3中实现联动的方法在4版本中并不好使,原因就是在antd4中表单内容的更新并不会触发页面的渲染。在antd4中我们有两种方法可以用来控制表单联动,那就是dependencies方法和shouldUpdate方法。

        对比了一下官方文档的两种方法,个人感觉

        dependencies适用于针对依赖字段重新触发校验逻辑的场景

        shouldUpdate适应于针对依赖字段对某一区域进行渲染的场景

        所以我们就采用shouldUpdate方法来处理联动。但是当我们实际开发过程中,如果我们是控制一个表单项的联动还好,如果同时控制多个表单项联动,有两种方案

// 方案1:

<Form.Item noStyle shouldUpdate={(prevValues, curValues) => { return prevValues.type !== curValues.type; }} >
    {() => {
        return <Form.Item label="名字" name={'name'} >
            <Input placeholder='请输入' />
        </Form.Item>
    }}
</Form.Item>
<Form.Item noStyle shouldUpdate={(prevValues, curValues) => { return prevValues.type !== curValues.type; }} >
    {() => {
        return <Form.Item label="年龄" name={'age'} >
            <Input placeholder='请输入' />
        </Form.Item>
    }}
</Form.Item>


// 方案2:
<Form.Item noStyle shouldUpdate={(prevValues, curValues) => { return prevValues.type !== curValues.type; }} >
    {() => {
        return <>
            <Form.Item label="名字" name={'name'} >
                <Input placeholder='请输入' />
            </Form.Item>
            <Form.Item label="年龄" name={'age'} >
                <Input placeholder='请输入' />
            </Form.Item>
        </>
    }}
</Form.Item>

        如果采用第一种方案,代码会比较冗余,而且如果表单有多处联动,不太容易区分哪个是联动哪个的,因为是平铺下来的嘛

        如果采用第二种方案,会很直观的看出来,某处联动会联动哪几个表单。但是这里有个坑,即使我们设置了noStyle和空标签,被关联的多个表单还是会被一个div包裹起来。这会带来的后果就是,假设一行只有一个固定字段,其他都是被关联的字段,当被关联字段超过了一行能容纳的个数的话会整体换行,导致第一行只留下一个字段,样式布局则会很奇怪。如图

        针对这个问题,目前还没想到完美的解决方案,如果有比较好想法的小伙伴,欢迎分享你的想法哟。

坑2:不管是通过dependencies方法还是shouldUpdate方法。当我们通过联动,隐藏某几个表单项后,已收集到form中的数据并不会删除。

<Form.Item noStyle shouldUpdate={(prevValues, curValues) => { return prevValues.type !== curValues.type }} >
    {({ getFieldValue }) => {
        const type = getFieldValue('type');
        if (type === '1') {
            return <>
                <Form.Item label="名字" name={'name'} >
                    <Input placeholder='请输入' />
                </Form.Item>
                <Form.Item label="年龄" name={'age'} >
                    <Input placeholder='请输入' />
                </Form.Item>
            </>
        } else if (type === '2') {
            return <Form.Item label="性别" name={'sex'} >
                <Input placeholder='请输入' />
            </Form.Item>
        }
        return null
    }}
</Form.Item>

        看下面代码,这段代码是当表单中type类型为1时 ,展示名字和年龄字段,当type为2时,展示性别字段

        如果我们将type切换成1再切换成2, 表单中会存在名字和年龄,但是在页面上并不存在这两个表单项。

        这并不会影响什么,但是个人感觉很不干爽,如果表单变大变复杂,提交表单时也会提交过去一些可能并不需要的字段。因此我们最好删除掉不需要的字段。

这个问题,能够直接想到两种方案。

        方案1:在最后提交表单的时候做一下特殊处理。将多余的字段删除后再提交。但是如果在提交前再次回显表单项的时候,还是会回显之前残留的数据,时机太晚。

        方案2:在表单联动隐藏的时候,对字段进行重置。考虑使用resetFields,但是经过实践并不好用。可以采用setFieldsValue或setFields对字段进行重置,在如下位置添加相应重置逻辑

<Form.Item noStyle shouldUpdate={(prevValues, curValues) => { return prevValues.type !== curValues.type }} >
    {({ getFieldValue }) => {
        const type = getFieldValue('type');
        if (type === '1') {
            {/** 重置表单内容,并初始化名字和年龄 */ }
            return <>
                <Form.Item label="名字" name={'name'} >
                    <Input placeholder='请输入' />
                </Form.Item>
                <Form.Item label="年龄" name={'age'} >
                    <Input placeholder='请输入' />
                </Form.Item>
            </>
        } else if (type === '2') {
            {/** 重置表单内容,并初始化性别 */ }
            return <Form.Item label="性别" name={'sex'} >
                <Input placeholder='请输入' />
            </Form.Item>
        }
        return null
    }}
</Form.Item>

        如果表单是固定的话,单独这样写是没啥问题的。

        如果我们使用formList来为字段提供数组化管理,动态增减表单项的话。上述方法则会出现一个新的坑。

坑3: formList重新渲染的问题

        在上述代码的基础上,如果我们通过formList来包裹的话。正常情况是相互并不干扰的,但是,如果我们使用formList的add或remove方法,则会触发formList的重新渲染,带来的后果则是,重置每一组的表单内容。

        解决办法是将重置逻辑写到type表单项的onchange方法中即可

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值