Formik имеет две опции, управляющие временем проверки: validateOnChange
и validateOnBlur
.
Проблема с использованием validateOnChange
- пользователь получит ошибки, когда они начнут печатать, скажем, электронную почту - потому что это недопустимо, когда вы только начали вводить первые буквы.
В случае validateOnBlur
- скажем, пользователь ввел неправильный адрес электронной почты, оставил поле, вернулся и исправил правильный адрес электронной почты - ошибка будет отображаться в любом случае, пока они не покинут поле, поэтому это также не работает для меня.
Чего я хотел бы добиться - впервые проверить поле на blur
и начать эту точку - на change
.
Каждое поле должно пройти это лечение индивидуально.
Я пытался найти нативные способы сделать это, но не смог найти ни одного, поэтому я придумал это решение, которое мне не очень нравится, потому что оно не безупречно:
TL;DR:
Я переопределяю стандартные onBlur
и onChange
, исходящие от реквизита Field
и a) onBlur
- помечаем поле как измененное один раз (вероятно, я мог бы использовать touched
здесь) b) onChange
Я проверяю, было ли поле затронуто один раз, и если да, - вызовите проверку
0) Отключить проверку
<Formik
validateOnChange={false}
validateOnBlur={false}
...
1) Добавлено changedFields
в мое состояние
public state: IState = {
changedFields: {}
};
2) Используйте специальный метод, который переопределяет значения по умолчанию onBlur
и onChange
<Field name="userName" render={(props: FieldProps<MyFormInterface>) => (
<input type="text" label={'Name'} {...formikCustomValidation(props, this)} />
)}/>
3) Способ. Передача реквизита Field и родительского компонента, в котором находится состояние с changedFields
function formikCustomValidation({ field, form }: FieldProps, ownerCmp: Component<any, any>) {
return {
...field,
onBlur: e => {
if (field.value !== form.initialValues[field.name]) {
ownerCmp.setState({
changedFields: {
...ownerCmp.state.changedFields,
[field.name]: true
}
});
}
field.onBlur(e);
setTimeout(form.validateForm);
},
onChange: e => {
field.onChange(e);
if (ownerCmp.state.changedFields[field.name]) {
setTimeout(form.validateForm);
}
}
};
}
Вопрос - есть ли способ сделать это проще?
Проблема с этим решением - если я отправляю и оставляю нетронутой форму, и появляются некоторые ошибки - значение фокуса и исправления не помечает поле как действительное - потому что это первое касание, а поле все еще находится в состоянии ожидания первого состояния размытия, которое предположительно заставить слушать «изменения».
В любом случае, поддержание этого может быть болезненным, поэтому ищите лучшее решение.
Спасибо!