Как настроить логику отображения ошибок в Formik?

#reactjs #formik

#reactjs #formik

Вопрос:

Formik имеет две опции, определяющие, когда происходит проверка: validateOnChange и validateOnBlur .

Проблема с использованием validateOnChange — пользователь будет получать ошибки при вводе, скажем, электронной почты — потому что это недопустимо, когда вы только начали вводить первые буквы.

В случае validateOnBlur — допустим, пользователь ввел неверное электронное письмо, покинул поле, вернулся и исправил на правильное электронное письмо — ошибка будет отображаться в любом случае, пока они не покинут поле, так что это также не работает для меня.

Чего я хотел бы достичь — впервые проверить поле на blur и начиная с этого момента — на change .

Каждое поле должно обрабатываться индивидуально.

Я пытался найти собственные способы сделать это, но не смог найти ни одного, поэтому я придумал это решение, которое мне не очень нравится, потому что оно не безупречно:

TL;DR: Я переопределяю стандартные onBlur и onChange исходящие из Field реквизитов и а) onBlur отмечаю поле как измененное один раз (возможно, я мог бы использовать touched здесь) б) 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) Метод. Передача реквизитов поля и родительского компонента, в котором находится состояние с 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);
      }
    }
  };
}
  

Вопрос в том, есть ли способ сделать это проще?
Проблема с этим решением — если я отправляю нетронутую форму и появляются некоторые ошибки — значение фокусировки и исправления не помечает поле как действительное — потому что это первое «касание», а поле все еще находится в статистике, ожидающей первого состояния размытия, которое должно заставить прослушивать «изменения».

В любом случае, поддерживать это может быть непросто, поэтому ищите лучшее решение. Спасибо!

Комментарии:

1. Разве это не поведение по умолчанию? Просто не устанавливайте validateOnChange и validateOnBlur , и Formik будет делать то, что вы описываете.

2. О, я не могу поверить, что пропустил это. Спасибо, приятель.