问题
由于项目需要实现一个为经销商添加管理员的功能。如下图所示:
要求:
- 至少添加一个管理员账号
- 需要对管理员手机号做格式校验,非空校验,去重校验;管理员姓名做非空校验
- 能够动态删除和添加管理员,并且格式化数据表单提交
实现
看到这里我们立马能够想到在通过数据实现,react语言的特殊性,通过数据反映dom的变化,所以对数据元素的添加和删除能够反映的dom元素。好了,原理知道了。接下来上代码
首先数据结构选择,数组的元素的数据结构如下:
constructor(props) {
super(props);
this.state = {
managerList: [{name: "", phone: ""}],
};
}
然后在render方法中构造一个组件数组,如下。
render() {
....
let {managerList} = this.state;
let managerNumber = managerList.length;
let managerComps = managerList.map((el, index) =>{
return (
<span key={index}>
<Row span={24}>
<Col span={8}>
<FormItem label="管理员姓名:" labelCol={{span: 10}} wrapperCol={{span: 12}}>
{getFieldDecorator(`name${index}`,{
initialValue: el.name,
rules: [{
required: true,
message: '请填写管理员姓名'
}]
})(
<Input />
)}
</FormItem>
</Col>
<Col span={8}>
<FormItem label="管理员手机号:" labelCol={{span: 8}} wrapperCol={{span: 12}}>
{getFieldDecorator(`phone${index}`,{
initialValue: el.phone,
rules: [{
required: true,
message: '请填写管理员手机号'
},{
pattern: /^1[3|4|5|7|8][0-9]\d{8}$/, message: '请输入正确的手机号'
},{
validator:this.phoneDuplicateValidator,
}],
})(
<Input />
)}
</FormItem>
</Col>
<Col span={4} style={{marginTop:6}}>
{index === 0 && managerNumber < 5 && <Button shape="circle" size="small" icon="plus" type="primary" style={{marginRight:10}} onClick={() => this.addManager()} />}
{((managerNumber > 1 && index === 0) || index > 0) && <Button shape="circle" size="small" icon="minus" type="default" onClick={() => this.delManager(index)} />}
</Col>
</Row>
</span>
)
});
return(
<Form >
<div className="ant-descriptions-title">
管理员账号
</div>
<div>
<div>
{managerComps}
</div>
</div>
</Form>
)
}
新增元素对应的addManager方法
collectManager = () =>{
const {getFieldValue, resetFields} = this.props.form;
const managerList = [];
let managerNumber = this.state.managerList.length;
for (let i = 0; i < managerNumber; i++){
let name = getFieldValue(`name${i}`);
let phone = getFieldValue(`phone${i}`);
//!!!!重要,如果不加此方法,则会在删除元素时,getFieldDecorator的initalValue属性不生效的问题
resetFields([`name${i}`,`phone${i}`]);
managerList.push({name: name, phone: phone});
}
return managerList;
}
addManager = () =>{
let managerList = this.collectManager();
managerList.push({name: "", phone: ""});
this.setState({managerList});
}
删除元素对应的delManager方法
delManager = (index) =>{
let managerList = this.collectManager();
//删除指定index的元素
managerList.splice(index,1);
this.setState({managerList});
}
元素去重校验方法
phoneDuplicateValidator = (rule, value, callback) =>{
const {getFieldValue} = this.props.form;
let managerNumber = this.state.managerList.length;
let count = 0;
for (let i = 0; i < managerNumber; i++){
let phone = getFieldValue(`phone${i}`);
if(phone === value){
count++;
}
}
count > 1 ? callback('管理员手机号码不能重复') : callback();
}
实现后的效果自己可以本地看一下,之所以要写这篇博客,是因为我在实现的过程中遇到了删除元素了initialValue属性不生效的问题。导致的结果就是每次都是删除最后一个元素(因为数组长度减一了)
为了解决这个问题我尝试了很多种方法,比如:
1.设置一个visible属性,每次删除后重新挂载数组元素
2.手动调用form组件的setFieldsValue设置值。
以上方法尝试后全部失败了。由于我就想是什么原因导致了这个问题,仔细查看antd官方文档。发现了resetFields这一段描述
然后我便尝试在每次操作时,重置控件的值。此问题随即解决了。
总结
当我们使用getFieldDecorator并用initialValue设定初始值时,当我们改变组件的值时,组件表现出的值也改变了,但这个值并不是initialValue设定的,其是组件内部的state值保持的,如果需要继续用initialValue来设定组件的值,我们需要调用resetFields方法使initialValue有效。
前端路漫漫,作为一个后端开发工程师,写前端感觉更难,大家互勉!!!