我知道这个问题已经被问了一千遍了,但是我不确定我是怎么做的。我已经阅读了大量的stackoverflow,我正在寻找的是:我怎么做错了?
因此请考虑以下功能:
setFormValues(fieldName, value) {
let values = this.state.values;
values[fieldName] = value;
this.setState({
values: values
}, () => {
debounce(() => {
this.setState({
validationErrors: validator(this.state.validations, this.state.values),
});
}, 350);
});
}
每次元素值更改时,我们都将其传递给表单(每个元素都是调用此函数的其自己的react类)。在表单中设置了值(用于过帐数据)之后,我们必须验证表单的值。
让我们看看验证器文件:
import React from 'react';
import moment from 'moment';
import startCase from 'lodash.startcase';
/**
* Validate the form values.
*/
export const validator = (validations, formValues) => {
let validationMessages = {};
for (const key in formValues) {
if (validations.hasOwnProperty(key)) {
const fieldValidations = validations[key];
const validationMessage = createValidationMessage(key, formValues[key], formValues, fieldValidations);
if (validationMessage !== null) {
validationMessages[key] = validationMessage;
}
}
}
return validationMessages;
}
/**
* Create a a validation message when the validatiom for the form value
* fails against the form field validations.
*/
const createValidationMessage = (fieldName, value, formValues, fieldValidations) => {
let message = null;
fieldValidations.forEach((fieldValidation) => {
if (fieldValidation.hasOwnProperty('cannot_percede_field')) {
if (formValues.hasOwnProperty(fieldValidation.cannot_percede_field)) {
const formValue = formValues[fieldValidation.cannot_percede_field];
if (isFutureDate(value, fieldValidation)) {
message = {
message: 'Date cannot be greator then today.',
isError: fieldValidation.show_error,
};
}
if (isDateLessThen(value, formValue, fieldValidation)) {
message = {
message: 'Date cannot be less then: ' + startCase(fieldValidation.cannot_percede_field) + '.',
isError: fieldValidation.show_error,
};
}
}
}
})
return message;
}
/**
* Is the date in question greator then date saved?
*/
const isFutureDate = (value, validationObject) => {
if (validationObject.cannot_be_future_date) {
return moment(value).isAfter(moment());
}
return false;
}
/**
* Is the date in question less then the date saved?
*/
const isDateLessThen = (value, formValue, validationObject) => {
if (validationObject.cannot_percede_field) {
return moment(value).isBefore(formValue);
}
return false;
}
我们要做的就是遍历值,检查验证器是否对该字段具有特定规则。在这种情况下,如果该字段的状态不能在另一个字段之前,则说明验证消息,如果所讨论的字段大于当前字段,则再次设置该消息。
出了什么问题?
如果我取消反跳,并且将其设置为带有验证消息的状态,那么如果有的话,表单输入将非常缓慢。但是验证有效并且消息正确显示。
如果我将防抖保持不变,并强制失败(例如,日期字段位于另一个日期字段之前),则不会发生任何事情。
我了解的问题是,我可能一遍又一遍地调用去抖,因此该函数从不触发。但是选择日期时,它只能调用一次,等待350毫秒,然后显示或不显示验证错误。
我在用去污线去抖(甚至无法正常工作)时怎么办?
答案 0 :(得分:1)
去抖动使用一个函数,并返回一个包装原始函数的新函数。每当调用包装函数时,它都会在调用包装函数之前等待定义的时间。如果再次调用包装器,则将包装的函数的调用延迟指定的时间,依此类推。去抖动通过维护内部计时器来工作。每当调用包装器时,计时器都会重置,并且仅当经过定义的时间而没有重置时,才会调用包装的函数。
使用去抖动功能时,您需要定义一次函数,并多次调用它。如果您继续创建一个新函数(例如需要在setState内部),则该函数的内部计时器将永远不会重置,因为您不会多次调用该函数。实际上,您会得到一个延迟,然后调用包装函数,等等。
我将生成一个validate
去抖动的函数,并在setState
的回调中调用它:
validate = debounce(() => {
this.setState(({ validations, values }) => ({
validationErrors: validator(this.state.validations, this.state.values),
}))
})
setFormValues(fieldName, value) {
let values = this.state.values;
values[fieldName] = value;
this.setState({
values: values
}, this.validate;
});
}
为什么您的验证这么慢?
虽然我同意@skyboyer的观点,即您不应该更改状态,但这可能不是验证缓慢的原因。查看验证,很明显,对于每个按键,脚本都会运行与所有表单输入相关的所有验证。其中两个验证使用moment.js来转换和比较日期,这非常慢。
由于您在运行setFormValues(fieldName, value)
时了解当前值,因此仅验证该字段。此外,只需一次转换formValues[fieldValidation.cannot_percede_field]
和将来的数据,并缓存结果以供使用,而不是在每次击键或转换时转换并使用本机js或更快的库。
仅一次约会moment.js
答案 1 :(得分:1)
“表单输入缓慢”的原因是您突变了state
,这对React来说是不行的。突变后,状态组件不会重新呈现。仅当去抖动的验证程序调用{{1}}时才会更新。
虽然我同意Ori Drori的意见,但您可能会改变您的逻辑,以肯定需要停止突变状态的其他方式来运行验证
setState
然后做
setFormValues(fieldName, value) {
let values = this.state.values;
// here you mutate this.state.values[fieldName]!
values[fieldName] = value;
this.setState({
values: values
}
相反。