Ant-design: why we always need `callback()` in validator function at Form component? 为什么表单验证的 rules 中使用 validator 时,其方法体总是需要调用 callback()

创建于 2017-03-03  ·  38评论  ·  资料来源: ant-design/ant-design

感谢提供 Form 等一系列组件。

问题描述

由于要在提交前,需要对表单内的各个 field 进行再次校验,使用了 validateFieldsAndScroll。但发现并未生效。

后来经调试,发现如果对该函数传入一组指定的 field,是可以生效的。但只要这组 fileds 中,包含了任意一个在校验规则中指定使用 validator 辅助校验的,则整个 validateFields 方法都不生效。

最后,才发现,是因为,我一开始并没有在对应的 validator 回调中,总是返回 callback() (觉得很多余,而且一开始不写也可以对单个 input 做正常校验)。加上以后就 ok 了。

疑惑

请问,这属于 bug 吗? 因为文档中并没有指出,validator 中必须要返回 callback()
如果确实是必须要返回 callback ,建议要在文档中提醒开发者注意,或者默认可以缺省。

代码片段

handleSubmit = (e) => {
        e.preventDefault()

        const { onSubmit } = this.props
        const { validateFieldsAndScroll, getFieldsValue, resetFields } = this.props.form

        validateFieldsAndScroll((err, values) => {
              if (!err) {
                  onSubmit(getFieldsValue())
              }
        })
}
handleConfirmPassword = (rule, value, callback) => {
        const { getFieldValue } = this.props.form
        if (value && value !== getFieldValue('newPassword')) {
            callback('两次输入不一致!')
        }

        // Note: 必须总是返回一个 callback,否则 validateFieldsAndScroll 无法响应
        callback()
 }

render()

<FormItem
    {...formItemLayout}
    label="确认密码"
>
{
    getFieldDecorator('confirmPassword', {
           rules: [{
                  required: true,
                  message: '请再次输入以确认新密码',
            }, {
                  validator: this.handleConfirmPassword
            }],
    })(<Input type="password" />)
}
</FormItem>

Environment

  • antd version: 最新
  • OS and its version: OS X
  • Browser and its version: chrome 最新
Usage ❓FAQ 🙅🏻‍♀️ WON'T RESOLVE

最有用的评论

被人吐槽了 https://www.zhihu.com/question/33629737/answer/150154145

可以加一个文档说明,我们做开源的原则之一是兵来将挡水来土掩。

所有38条评论

它的设计: https :

顺便说一句,如果不使用callback来通知异步验证器,它如何知道异步过程已结束?

被人吐槽了 https://www.zhihu.com/question/33629737/answer/150154145

可以加一个文档说明,我们做开源的原则之一是兵来将挡水来土掩。

文档已更新。

你好是否 这种用法 只能用 class 的写法?
能否用 纯函数的 写法 写 React Component .如果有,有没有案例啊?

这个API设计真的是很不优雅,感受下我只是想做一下某个checkbox是否选中的检查:

rules: [
            {
              message: 'You need to agree to our terms to sign up.',
              validator: (rule, value, cb) => (value === true ? cb() : cb(true)),
            },
          ],

并且给到callback的第一个参数是错误信息,和message也是冗余(虽然似乎只要返回任何东西都会使用message了,应该是message 覆盖了错误信息)。

大部分使用者预期的使用方式应该是直接返回true或者false来决定对错:

rules: [
            {
              message: 'You need to agree to our terms to sign up.',
              validator: (rule, value, cb) => value === true,
            },
          ],

可用,但是还是建议优化这个API,即使用的是 https://github.com/yiminghe/async-validator/,但是ANT这边完成全可以在调用上封装一下

@neekey 可以去给 async-validator 提个兼容的 PR

@neekey 这种奇怪的接口是为了实现:

  • 异步的validation
  • 支持不同的错误返回不同的message

有没有更好的方式啊?

<Row>
                <Col span={24} key={"method"}>
                    <FormItem {...formItemMethodLayout} label="请求方法">
                        {getFieldDecorator("method", {
                            initialValue: this.state.data.method,
                            validateTrigger: "onChange",
                            rules: [{
                                required: true,
                                message: `请选择请求方法`
                            }, {
                                //validator: this.state.checkUnique ? this.checkConfirmMethod.bind(this) : (rule, value, callback) => {callback();},
                                validator: (这如何判断当前组件是否开始校验了) ?
 this.checkConfirmMethod.bind(this) : (如果不是当前组件开始校验,就调用其他函数),
                            }]
                        })(
                            <Select placeholder={"请选择请求方法"} onChange={::this.handleChange.bind(this)}>
                                {this.state.apiRequestMethodSelect}
                            </Select>
                        )}
                    </FormItem>
                </Col>
            </Row

每次碰到函数的校验,都会来这里看一次,真的不好记

validator 函数

startNumValidator = (rule, value, callback) => {
    const { exportDataCount } = this.props;
    const reg = /^[1-9][0-9]*$/;
    let errors = [];
    if (!reg.test(value) || value > exportDataCount) {
      errors.push(new Error('illegal value'));
    }
    callback(errors);
  }

不是统一callback errors么,也挺合理的啊感觉
不知道新版的antd开始区分异步和同步校验了没? validator(同步) asyncValidator(异步)

在请求后,后台返回的回调里面怎么调用这个消息提示

在使用rule中validator 做自定义校验,遇到一个问题
validateFunc = (rule, value, callback) => {
if (true) {
console.log(11);
callback('Error message');
return;
}
callback();
};
我想要校验结果'Error message'在对应的FormItem组件下显示,但是callback执行后,'Error message'没有在对应的FormItem组件下显示,而是在控制台打印出来,这是为什么?

在对应的FormItem组件下显示的逻辑是怎么书写的?

@neekey 可以去给 async-validator 提个兼容的 PR

有人提了,yiminghe说,反对。callback 更直接。都9102年了,还用callback,坐等真香

在对应的FormItem组件下显示的逻辑是怎么书写的?

我把自定义校验的方案改了,在onFieldsChange()中判断,不符合自定义的规则就直接改errors,然后就会在控件中显示error信息
onFieldsChange(props, changedFields) { const { dispatch, detail } = props; const finalChangedFields = { ...changedFields }; // 校验时间大小是否符合规则 if ( _.has(changedFields, 'currentDate') && detail?.targetDate && compareCurrentTimeEarlierThanTargetTime( finalChangedFields.currentDate, detail?.targetDate ) ) { finalChangedFields.currentDate.errors = [ { message: 'current Date should be latter than target Date', field: 'currentDate', }, ]; } dispatch({ type: 'controllerModel/saveDetail', payload: { changedFields: finalChangedFields, data: detail, }, }); }

校验通过后下面的提示不消失是怎么回事

问一个问题,这个validator能不能在页面加载的时候,不做校验?

@neekey
必须调用回调功能是异步情况下的一大缺点:

<Form>
          <Form.Item ...>
            {getFieldDecorator('name', {validator: (rule, value, callback) => setTimeout(callback(), 1000)})(
                <Input placeholder="name" />
            )}
          </Form.Item>
....

在 setTimeout 被触发之前,整个组件被卸载。 然后超时被触发,它的回调被触发并且

组件将使用setState (我猜)这将导致以下错误:

警告:无法对卸载的组件执行 React 状态更新。 这是一个空操作,但它表明您的应用程序中存在内存泄漏。 要修复,请取消 componentWillUnmount 方法中的所有订阅和异步任务。

遗憾的是回调不可取消! 没有办法避免这个错误!

@九峰大地
我遇到了这个问题。
我的解决方案是将undefined传入callback 。 当callback的第一个参数是空数组时,验证器将通过。 并且它为参数设置了一个默认值,所以undefined也是有效的。

callback定义: L146

为什么我自定义验证通过了 还出现async-validator: [""] ,

如果有两个校验的话,第一个会失效,为什么?
```
rules: [
{
required: true,
message: '请输入手机号',
},
{
validator: (rule, value, callback) => {
try {
if (this.props.form.getFieldValue('prefix') == 86 && value) {
const reg = /^1d{10}$/;
if (!reg.test(value)) {
throw new Error('Something wrong!');
}
}
} catch (err) {
callback(err);
}
},
message: '请输入有效手机号',
},
],

 rules: [
                {
                  required: true,
                  message: '请输入手机号',
                },
                {
                  validator: (rule, value, callback) => {
                    try {
                      if (this.props.form.getFieldValue('prefix') == 86 && value) {
                        const reg = /^1\d{10}$/;
                        if (!reg.test(value)) {
                          throw new Error('Something wrong!');
                        }
                      }
                    } catch (err) {
                      callback(err);
                       return // +
                    }
                     callback() // +
                  },
                  message: '请输入有效手机号',
                },
              ],

在使用rule中validator 做自定义校验,遇到一个问题
validateFunc = (rule, value, callback) => {
if (true) {
console.log(11);
callback('Error message');
return;
}
callback();
};
我想要校验结果'Error message'在对应的FormItem组件下显示,但是callback执行后,'Error message'没有在对应的FormItem组件下显示,而是在控制台打印出来,这是为什么?

在使用rule中validator 做自定义校验,遇到一个问题
validateFunc = (rule, value, callback) => {
if (true) {
console.log(11);
callback('Error message');
return;
}
callback();
};
我想要校验结果'Error message'在对应的FormItem组件下显示,但是callback执行后,'Error message'没有在对应的FormItem组件下显示,而是在控制台打印出来,这是为什么?

你解决了吗,遇到同个情况

 rules: [
                {
                  required: true,
                  message: '请输入手机号',
                },
                {
                  validator: (rule, value, callback) => {
                    try {
                      if (this.props.form.getFieldValue('prefix') == 86 && value) {
                        const reg = /^1\d{10}$/;
                        if (!reg.test(value)) {
                          throw new Error('Something wrong!');
                        }
                      }
                    } catch (err) {
                      callback(err);
                       return // +
                    }
                     callback() // +
                  },
                  message: '请输入有效手机号',
                },
              ],

message提示不会重复吗?'请输入手机号 请输入有效手机号' 类似这样

 rules: [
                {
                  required: true,
                  message: '请输入手机号',
                },
                {
                  validator: (rule, value, callback) => {
                    try {
                      if (this.props.form.getFieldValue('prefix') == 86 && value) {
                        const reg = /^1\d{10}$/;
                        if (!reg.test(value)) {
                          throw new Error('Something wrong!');
                        }
                      }
                    } catch (err) {
                      callback(err);
                       return // +
                    }
                     callback() // +
                  },
                  message: '请输入有效手机号',
                },
              ],

message提示不会重复吗?'请输入手机号 请输入有效手机号' 类似这样

不会

image

做如下操纵
image

为什么红色的校验还不消失呢???都满足规格了 这种相互影响的校验怎么做???

rule的validator 成功失败与否都要调用callback,区别是传不传参数

在使用rule中validator 做自定义校验,遇到一个问题
validateFunc = (rule, value, callback) => {
if (true) {
console.log(11);
callback('Error message');
return;
}
callback();
};
我想要校验结果'Error message'在对应的FormItem组件下显示,但是callback执行后,'Error message'没有在对应的FormItem组件下显示,而是在控制台打印出来,这是为什么?

在使用rule中validator 做自定义校验,遇到一个问题
validateFunc = (rule, value, callback) => {
if (true) {
console.log(11);
callback('Error message');
return;
}
callback();
};
我想要校验结果'Error message'在对应的FormItem组件下显示,但是callback执行后,'Error message'没有在对应的FormItem组件下显示,而是在控制台打印出来,这是为什么?

你解决了吗,遇到同个情况

我也遇到了这个问题, 如果initialvalue为空, 在正常输入内容后通过onblur时间可以正常触发自定义校验器并有错误的情况下会进行提示, 但一旦初始initialvalue是有值的情况下, 在validatefields 进行所有表单组件统一校验时, err打印出来是null, 过了一会后 又会在控制台弹出校验失败, 自定义验证器是异步action

我觉得你把函数里的return;删掉,再试一试,或许有用。

------------------ 原始邮件 ------------------
发件人: "Ivan-hl"<[email protected]>;
发送时间: 2019年11月20日(星期三) 下午5:19
收件人: "ant-design/ant-design"<[email protected]>;
抄送: "wk"<[email protected]>; "Manual"<[email protected]>;
主题: Re: [ant-design/ant-design] why we always need callback() in validator function at Form component? 为什么表单验证的 rules 中使用 validator 时,其方法体总是需要调用 callback() (#5155)

在使用rule中validator 做自定义校验,遇到一个问题
validateFunc = (rule, value, callback) => {
if (true) {
console.log(11);
callback('Error message');
return;
}
callback();
};
我想要校验结果'Error message'在对应的FormItem组件下显示,但是callback执行后,'Error message'没有在对应的FormItem组件下显示,而是在控制台打印出来,这是为什么?

在使用rule中validator 做自定义校验,遇到一个问题
validateFunc = (rule, value, callback) => {
if (true) {
console.log(11);
callback('Error message');
return;
}
callback();
};
我想要校验结果'Error message'在对应的FormItem组件下显示,但是callback执行后,'Error message'没有在对应的FormItem组件下显示,而是在控制台打印出来,这是为什么?

你解决了吗,遇到同个情况

我也遇到了这个问题, 如果initialvalue为空, 在正常输入内容后通过onblur时间可以正常触发自定义校验器并有错误的情况下会进行提示, 但一旦初始initialvalue是有值的情况下, 在validatefields 进行所有表单组件统一校验时, err打印出来是null, 过了一会后 又会在控制台弹出校验失败, 自定义验证器是异步action


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub, or unsubscribe.

太坑了

校验函数里面如果出现异常,没有任何提示。
坑了半天。。。

我在想这个AntdV是不维护了么

@kongling94 ?

同样遇到这个问题,没下文了?

<a-input id="code" placeholder="请输入用户ID"v-decorator="[ 'code', {rules: [{ required: true, message: '请输入用户ID' }, { validator: handleUsername }], validateTrigger: 'change'} ]" > </a-input>
handleUsername(rule, value, callback) { value = value.trim() if (value.length == 0) { this.username = ''; callback(); } else { fetchUsername({ code: value }) .then((rest) => { if (rest.code == 200) { this.username = rest.data; //callback(); } else { this.username = ''; callback(new Error(rest.msg)) return; } }).finally(() => { callback() }) } },
<a-form :label-col="labelCol" :wrapper-col="wrapperCol" :form="form" @submit="handleSubmit"> <a-button type="primary" htmlType="submit">确定</a-button> </a-form>
点确定没有任何反应 不进行任何提示,在console 里面输入async-validator:["code is required"]
根本没有进validateFields
去掉 validator 和 validateTrigger 点确定就会正常提示。
这是什么问题?

<a-input id="code" placeholder="请输入用户ID"v-decorator="[ 'code', {rules: [{ required: true, message: '请输入用户ID' }, { validator: handleUsername }], validateTrigger: 'change'} ]" > </a-input>
handleUsername(rule, value, callback) { value = value.trim() if (value.length == 0) { this.username = ''; callback(); } else { fetchUsername({ code: value }) .then((rest) => { if (rest.code == 200) { this.username = rest.data; //callback(); } else { this.username = ''; callback(new Error(rest.msg)) return; } }).finally(() => { callback() }) } },
<a-form :label-col="labelCol" :wrapper-col="wrapperCol" :form="form" @submit="handleSubmit"> <a-button type="primary" htmlType="submit">确定</a-button> </a-form>
点确定没有任何反应 不进行任何提示,在console 里面输入async-validator:["code is required"]
根本没有进validateFields
去掉 validator 和 validateTrigger 点确定就会正常提示。
这是什么问题?

请问你这个问题解决了吗?同样碰到了这个问题

<a-input id="code" placeholder="请输入用户ID"v-decorator="[ 'code', {rules: [{ required: true, message: '请输入用户ID' }, { validator: handleUsername }], validateTrigger: 'change'} ]" > </a-input>
handleUsername(rule, value, callback) { value = value.trim() if (value.length == 0) { this.username = ''; callback(); } else { fetchUsername({ code: value }) .then((rest) => { if (rest.code == 200) { this.username = rest.data; //callback(); } else { this.username = ''; callback(new Error(rest.msg)) return; } }).finally(() => { callback() }) } },
<a-form :label-col="labelCol" :wrapper-col="wrapperCol" :form="form" @submit="handleSubmit"> <a-button type="primary" htmlType="submit">确定</a-button> </a-form>
点确定没有任何反应 不进行任何提示,在console 里面输入async-validator:["code is required"]
根本没有进validateFields
去掉 validator 和 validateTrigger 点确定就会正常提示。
这是什么问题?

请问你这个问题解决了吗?同样碰到了这个问题

// 自定义密码校验
  handleConfirmPassword = (rule, value, callback) => {
    const { getFieldValue } = this.props.form;
    if (value && value !== getFieldValue('newPwd')) {
      callback('两次输入不一致!');
    }

    // Note: 必须总是返回一个 callback,否则 validateFieldsAndScroll 无法响应
    callback();
  };
我是这么解决的

validatorFun(规则,值,回调){
const psw = this.form.getFieldValue('newPwd')
if (value && value !== psw) {
rule.message = '淋漓泡泡'
回调(规则)
}
打回来()
}

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

drcmda picture drcmda  ·  3评论

longzb picture longzb  ·  3评论

shivekkhurana picture shivekkhurana  ·  3评论

plandem picture plandem  ·  3评论

alanwei0 picture alanwei0  ·  3评论