问题是这样的:
环境:
antd@4.x
现象:
如上页面
- 出现页面后直接点击按钮触发校验,不会有校验提示,页面没有任何反应
- 假如只有其中任何一个,校验正常 比如,没有“模型编码”,只有“模型名称”
- 假如先手动在一个框里输入,之后正常 比如,先在“模型名称”里面输入一个值,之后再点按钮
背景:
“模型名称”和“模型编码”都是antd@4.x - Form,使用Form的validator进行校验
界面代码大致如下
<Form.Item label="模型名称">
{getFieldDecorator('name', {
rules: [
{ validator: checkModelCode },
],
})(<Input />)}
</Form.Item>
<Form.Item label="模型编码">
{getFieldDecorator('key', {
rules: [
{ validator: checkModelCode },
],
})(<Input />)}
</Form.Item>
调用的方法,代码大致如下:
checkModelCode: [
function*({ delayTimeout, callback }, { call }) {
if (delayTimeout) {
yield call(delay, delayTimeout);
}
try {
const { res } = yield call(checkModelCode);
if(callback){
callback(res);
}
} catch (err) {
if(callback){
callback();
}
}
},
{ type: 'takeLatest' },
]
原因:
上面的checkModelCode方法中,callback是form的validator方法的参数,作为参数传给了checkModelCode方法
不论校验是否通过,callback方法都是要执行的。否则就无法出现预期的校验效果
而校验方法checkModelCode是takeLatest类型,也即只响应最新的请求。所以,
当我们点击按钮触发校验时,“模型编码”和“模型名称”都会调用checkModelCode,此时只有后一个请求会被响应,也即前一个请求被取消掉,那对应的callback方法也无法被执行到,因此页面没有校验效果。
类似于官网:
之所以在一个框里输入值之后,一切正常,大概是因为输入值已经触发了对这个框的校验。因此,之后点击按钮对整个表单进行校验的时候,antd不会再校验这个表单。
解决办法:
不想去掉takeLatest的话,可以给两个表单分别定义校验的方法,如下:
validateModelName: [
function*({ callback, delayTimeout }, { call }) {
if (delayTimeout) {
yield call(delay, delayTimeout);
}
},
{ type: 'takeLatest' },
],
validateModelKey: [
function*({ callback, delayTimeout }, { call }) {
if (delayTimeout) {
yield call(delay, delayTimeout);
}
},
{ type: 'takeLatest' },
],
其实按照逻辑也应该是这样,自身表单防止连点,不能俩表单的请求混着一起处理呀