Ant Design - Form

这里发现一个 Form 组件的一个需要注意的点。
情形:父组件使用map嵌套子组件,子组件里面有表单填写的内容,使用了Form.getFieldDecorator 属性,如果嵌套的子组件只有几个,则没有问题,如果嵌套的子组件达到几十个,那么会造成页面填写数据时出现卡顿的现象。
代码如下:

<Form onSubmit={this.handleSubmit}>
   <FormItem {...formItemLayout} label="设备名">
     {getFieldDecorator('name', {
       rules: [
         {
           required: true,
           message: '请输入设备名',
         },
       ],
     })(<Input placeholder="请填写" />)}
   </FormItem>
 </Form>

来看一下 antd 对 getFieldDecorator 属性的描述

在这里插入图片描述

【经过 getFieldDecorator 包装的控件,表单控件会自动添加 value 、onChange(或 trigger 指定的其他属性),数据同步将被 Form 接管】
这句的意思呢,如上图代码所示,在form的组件中,用 getFieldDecorator 包装控件,就会为表单中的包装组件自动加上value 、onChange 两个属性,就像示例中的 input 组件,接下来我们就可以用 form.validateFields 属性获取到这个包装组件的值了。这句话不好理解,来看下一般情况下获取组件的代码,就好理解多了。

<FormItem label="年龄:" 
	<input
	  type="number"
	  value={age.value || ''}
	  onChange={(e) => onFormChange('age',+e.target.value)}
	/>
</FormItem>

这段代码是在 state中设置了input组件的值,然后通过 onChange 组件改变 state中input组件的值,如果用了 getFieldDecorator 那就不用额外设置了。

问题出现的原因:
回到之前出现问题的情形,页面出现卡顿的问题原因是,当我们有七十个子组件时,在任意一个组件中填写数据,即使只填入一个数字,也会造成七十个子组件重新渲染。

解决方法:
当然,这里又一个解决方法,在父组件使用map生成子组件的时候,就为每个子组件设置一个唯一的id,然后使用生命周期中的 shouldComponentUpdate 做渲染判断,这样就能只渲染一个子组件。不过这个方法存在一些坑,比如对于 Modal 组件的点击后渲染,还需要做些额外的操作。如果可以的话,可以使用原生写,自定义 onChange 函数。

解决方法的部分代码:

shouldComponentUpdate (nextProps, nextState){
  if(nextProps.pollinginstance.activeNum===this.props.number) {
      return true;
    } 
    return false;
  }

深入解析 Form 源码:
为什么会出现只填写一个数据,整个组件就会重新渲染呢?可以看出,是由 Form 中的 onChange 函数引起的,使用React Developer Tools 可以看一下 input 这个组件,value 和 onChange 都是自动添加的。
以下是在网上找到的相关源码

在这里插入图片描述

// 代码片段一
onCollect(name_, action, ...args) {  
  const { name, field, fieldMeta } = this.onCollectCommon(name_, action, args);
  const { validate } = fieldMeta;
  const newField = {
    ...field,
    dirty: hasRules(validate),
  };
  // setFields请查看代码片段二
  this.setFields({
    [name]: newField,
  });
},
// 代码片段二
setFields(maybeNestedFields) {  
  const fields = this.fieldsStore.flattenRegisteredFields(maybeNestedFields);
  this.fieldsStore.setFields(fields);
  if (onFieldsChange) {
    const changedFields = Object.keys(fields)
      .reduce((acc, name) => set(acc, name, this.fieldsStore.getField(name)), {});
    onFieldsChange(this.props, changedFields, this.fieldsStore.getNestedAllFields());
  }
  this.forceUpdate();
},

在代码二中可以看到,新的数据保存在 fieldsStore 里之后,调用了 this.forceUpdate() 这是强制页面刷新的函数。

所以,我目前的猜想是,Form 引起的组件重新渲染,是由于改变了props 属性的值,由于 props 值改变,shouldComponentUpdate 函数判断要重新渲染,这也就是达到了一个实时更新的效果。如果组件少,那么这种实时刷新就不会造成太大的影响,如果组件多,那么就要考虑继续用 Form 是否合适了。

参考链接:
http://ju.outofmemory.cn/entry/348216

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值