问题

在做antd项目时发现,使用Form.create()(xxx)创建的模块里面的Form表单提交前可以使用this.props.form.validateFieldsAndScroll()判断是否校验成功,this.props.form也就是整个页面模块的Form,那么,如果页面上有多个Form,此时再使用this.props.form.validateFieldsAndScroll()判断校验结果就是对整个页面的Form进行判断,并不能够对单个Form校验结果做判断,问题就在此,如何对单个Form做判断?

解决方法

  1. 手动校验,通过对表单元素添加change事件监听,获取表单元素值,手动做校验,这不失为一个方法,但有违react设计的思想。
  2. 把表单作为一个组件独立出去,页面通过props传入表单组件需要的值,在表单组件内部单独维护相关逻辑,这也是本文推荐的方式。

案例实现

Form子组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import React, { Component } from 'react';
import {Button, Form, Input, Select} from 'antd';

const FormItem = Form.Item;

class Forms extends Component{
getItemsValue = ()=>{
const val= this.props.form.getFieldsValue(); // 获取from表单的值
return val;
}
render(){
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 8 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 16 },
},
};
const { form, initValue1, initValue2, initValueList } = this.props;
const { getFieldDecorator } = form; // 校验控件
return(
<Form style={{backgroundColor: '#fff', padding: '20px'}}>
<FormItem
{...formItemLayout}
label={`相关数量`}
>
{getFieldDecorator(`amount`,{
rules: [{
message: '必填字段!',
required: true
}],
initialValue: initValue1 ? initValue1 : undefined
})(
<Input placeholder="请输入"/>
)}
</FormItem>
<FormItem
{...formItemLayout}
label={`选择相关名称`}
>
{getFieldDecorator(`name`,{
rules: [{
message: '必填字段!',
required: false
}],
initialValue: initValue2 ? initValue2 : undefined
})(
<Select
placeholder="请选择"
onChange={this.handleSelectChange}
>
{
initValueList && initValueList.map((x, i) => (
<Option value={x.Id} key={i}>{x.name}</Option>
))
}
</Select>
)}
</FormItem>
</Form>
)
}
}

export default Form.create()(Forms); //创建form实例

Form子组件,接收父组件传过来的初始数据,组件中getItemsValue自定义方法返回表单的值,需要在父组件中调用。

父组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import React, { Component } from 'react';
import { Modal, Button } from 'antd';
import Forms from './Forms'

export default class Modals extends Component {
constructor(props) {
super(props);
this.state = {
visible: false,
initValue1: 0,
initValue2: 'myName',
initValueList: ["李云龙", "李荣基", "李达"]
};
}
handleClick = () => {
this.setState({
visible: true
})
};
handleCreate = () => {
let values = this.formRef.getItemsValue();
// 获取到子组件form的值,做进一步操作
this.setState({
visible: false
})
};
render() {
return (
<section>
<Modal
visible={this.state.visible}
title="编辑"
onOk={this.handleCreate}
onCancel={() => {
this.setState({ visible: false });
}}
okText="保存"
cancelText="取消"
>
<Forms
initValue1={initValue1}
initValue2={initValue2}
initValueList={initValueList}
wrappedComponentRef={(form) => this.formRef = form}
/>
</Modal>
<Button onClick={()=>{ this.handleClick }}>点击弹框</Button>
</section>
);
}
}

这里关键的是使用wrappedComponentRef属性拿到这个Form的ref,简单的理解为拿到子组件的form实例,因此,可以在handleCreate函数中通过this.formRef.getItemsValue()调用自子组件的方法获取返回的form值。至此,上面的问题就解决了。

关于wrappedComponentRef的描述详见antd官网描述