踩坑日记:关于antd表单封装回传值至父组件的问题

gogogo.jpg

写在前面(说几句废话)

ant design是一套非常优秀的组件库,其中有react版本和vue版本,二者除了语法 上的差异,使用思想基本大同小异,其中ant design 的Form组件又是使用频率非常高的组件,但往往,我们在做一些复杂功能的时候,通常需要对其进行二次封装,于是我就遇到了这样的问题
“React和Vue都是作为单向数据流的框架,我们通常是使用‘父传子,子调父’的形式来做组件通信的,对我封装的表单组件,怎么才能将子组件的值暴露在父组件中供父组件的Form方法捕获,并同意操作值或者校验呢??”
这个问题困扰了我很久,以至于很长一段时间我都是通过回调函数的形式来和父组件通信的,即,父组件传一个操作Form的方法到子组件,子组件在完成特定的事件后,调用这个方法。但这样用起来,我们还得多传一个回调函数,并且在表单统一校验和取值方面也不行,但是没办法,于是,他像一根刺一样埋在了我心里,我总感觉不能和原组件使用方法相同的封装用起来很闹心。
一个偶然的机会,我发现,原来我没有深刻体会到官方文档中的这句话

form.PNG

当年的我还是一个小白,面对复杂的开发,我对这句话的认识只是固定在了现有组件的上面,包括他的valuedefaultevalue等,而忽略了他对于自定义组件封装的重要作用,真是这句话,真正解决了子组件像父组件回传值的问题。我们不再使用callback的形式了!好,下面开始进入正题。
为尽可能解决大家遇到的问题,这边文章,我将分别使用React和Vue来实现一些功能,供大家参考

Antd中表单封装回传值至父组件

本文不管是antd4.x还是3.x还是ant design vue都适用,这里我使用的是react版本的3.x。
对于上面官网的那句话,现在应该有一个更明确的理解,要想我们的组件可以搭配Form组件使用,并和原生组件用法相同,我们的组件需要遵循以下几点

  • 提供受控属性 value 或其它与 valuePropName的值同名的属性。
  • 提供 onChange 事件或 trigger 的值同名的事件
  • 支持 ref:

下面我们来实践以下如何遵循上面的几条规定

自定义Input组件(React版本)

这里先用react版来做第一个实验,我将组件做了下面的封装和使用

父组件中

import React from 'react'
import CustomInput from './components/CustomInput '

const FormItem = Form.Item;
const Parent= props => {
    const { getFieldDecorator } = props.form
    const getValue = () => {
        props.form.validateFields((err, val) => {
            if(!err) {
                console.log(val)
            }
        })
    }
    const setValue = () => {
        props.form.setFieldsValue({title: '909090'})
    }
    return (
        <>
            
            
            
{getFieldDecorator('title', { })()}
) } export default Form.create()(Parent)

父组件就是一个常规的对Antd表单项的使用,主要内容是对自定义表单的取值和校验以及对其设值。下面是子组件封装方法

import React from 'react'
import { Input } from 'antd'

const PriceInput = (props, ref) => {
    const inputChange = e => {
        const { onChange } = props
        onChange(e.target.value)
    }
    return ()
}
export default React.forwardRef(PriceInput)

我们没有做太复杂的封装,主要目的是为了演示如何遵循正确的规则去配合Form组件的使用。上面的组件有以下几点特点

  • 有value属性受控

  • 提供 onChange 事件,这里是最重要的一点,可以看到代码中有Input组件自带的onChange事件,有从props中取的onChange事件,那么规则中的onChange事件指的是哪一个呢?答案是props中的onChange,这一步很管家

  • 支持ref,因为class组件本身支持ref这里我特意用函数组件做实例,看其如何用

这次我们再来对上面那所谓的规律做总结

通过getFieldDecorator包装后,组件自带value属性,或者指定的valuePropName属性,我们可以通过这个特点 来设置组件的值,达到父组件驱动父组件的目的

通过getFieldDecorator包装后,组件自带onChange属性,我们可以通过调用这个方法,将值回传给父组件这是相当关键的一步,也是我一直忽略了的一点

自定义Upload组件(Vue版本)

上面我们用react版本的antd演示了如何做正确的做表单项封装,对于需要遵循的规定,也是用了比较常规的value和onChange,下面我们来使用vue版本来演示更复杂的使用方式,思想和上面的简单实例一样。

首先是父组件


  
   
  

父组件中,我们设置了triggervaluePropName,即规则中的第一条和第二条。二者都是自定义字段。其中trigger是我们回传值的时候要调用的方法,valuePropName是我们要注入到子组件中的属性。
看子组件封装



上面为官网完整demo,大家在实际项目中可根据情况封装更复杂的组件,集中上面的代码关键点在以下

  • props: {
      fileList: Array // 因为通过v-decorator包装后会自动注入valuePropName属性
    }
    
    
  • handleChange (info) {
      this.$listeners.uploadDone(info.fileList) // 这里我是本地,所以将该方法放在了一开始,可根据需求决定放在哪里,一般是放到文件上传完成后
    

我们通过this.$listeners.uploadDone来将值回传,从而保证父组件可以通过Form方法获取值。说实话我也是找了半天才从this.$listeners里找到uploadDone,其中uploadDone是我们在父组件自定义的trigger,这里为了讲解我故意设置了一下,不设置的话,取默认的onChange即可。

关于自定义校验

通过上面正确的封装后,我们已经可以通过Form来获取组件暴露的值了,这样我们在做一些自定义检验的时候,就可以使用validator做自定义校验了

总结

通过上面的封装,我们就可以正常的像用原生antd组件那样使用自定义的组件了,不管你是react用户还是vue用户,思想都是一样,一定要记住上面的三条规范,同时页要反思,文档要深刻理解哦好了,去试试吧本人已亲测有效

你可能感兴趣的:(踩坑日记:关于antd表单封装回传值至父组件的问题)