Как проверить два поля пароля с помощью Joi в TS React?

Я создаю компонент формы многократного использования с помощью TypeScript, назовем его пока AbstractForm. Он предназначен для наследования другими компонентами, такими как LoginForm, RegisterForm и так далее, допустим, я работаю над некоторым DerivedForm компонентом. Для проверки полей я использую Joi. Производный компонент должен только предоставить модель предметной области (схему проверки Joi) и метод отправки.
Все работает отлично и отлично проверяется, за исключением случаев, когда я хочу использовать два поля пароля, а второй пароль проверяется на соответствие первому через Joi.string().valid(this.state.data.password). Он никогда не проходит проверку, даже если оба пароля идентичны, Joi все равно выдает ошибку, говоря, что это не так. И я даже не могу придумать, почему. Может ли кто-нибудь предложить причину такого поведения?
Вместо этого я не использую Joi.ref('password'), потому что поля проверяются изолированно с каждым событием onChange (это делает метод validateProperty() в AbstractForm).

Это интерфейс схемы, определенный в модуле AbstractForm:

export interface Schema {
  [key: string]: Joi.Schema;
}

Это моя схема в DerivedForm:

schema: Schema = {
name: Joi.string()
  .required()
  .min(1)
  .label('Name'),
email: Joi.string()
  .required()
  .email()
  .min(5)
  .label('Email'),
password: Joi.string()
  .required()
  .min(8)
  .label('Password')
  .error(
    errors => 'Passwords should match and have at least 8 characters.'
  ),
repeatPassword: Joi.string()
  .valid(this.state.data.password)
  .required()
  .label('Password')
  .error(
    errors => 'Passwords should match and have at least 8 characters.'
  ),
};

И вот как эти поля проверяются внутри AbstractForm:

validateProperty = (name: string, value: string) => {
  const property = { [name]: value };
  const propSchema: Schema = { [name]: this.schema[name] };
  const { error } = Joi.validate(property, propSchema);
  return error ? error.details[0].message : null;
};

handleChange = (e: ChangeEvent<HTMLInputElement>) => {
  const { name, value } = e.currentTarget;

  const data = { ...this.state.data };
  data[name] = value;

  const errors = { ...this.state.errors };
  const errorMessage = this.validateProperty(name, value);
  if (errorMessage) errors[name] = errorMessage;
  else delete errors[name];

  this.setState({ data, errors });
};

Я также знаю, что this.setState(), а также новые useState() вызовы являются асинхронными, но здесь мы говорим о проверке по другому полю, поэтому это не должно быть проблемой.
При необходимости я могу добавить весь код для обоих модулей. Заранее спасибо!


person Artyom Khudyakov    schedule 26.02.2020    source источник


Ответы (1)


Получается, что действительная ссылка на первое поле пароля генерируется только при монтировании компонента. Чтобы обновить ссылку, вы можете добавить этот фрагмент кода:

  componentDidUpdate() {
    this.schema.repeatPassword = Joi.string()
      .min(8)
      .valid(this.state.data.password)
      .required()
      .label('Password')
      .error(
        errors => 'Passwords should match and have at least 8 characters.'
      );
  }

... чтобы он мог запомнить новое действительное значение. Я думаю, что это происходит потому, что я использую компонент класса, а не функциональный компонент. А с функциональным компонентом схема будет обновлять каждый рендер самостоятельно.

person Artyom Khudyakov    schedule 08.07.2020