Как правильно использовать метод SetError Formik?(Реактивная библиотека) - PullRequest
0 голосов
/ 25 октября 2018

Я использую React для связи с бэкэндом.Теперь пытаемся правильно реализовать Formik (Библиотека форм).

Основной вопрос: Как правильно использовать метод setError Formik?

Ошибки проверки на стороне клиента отображаются правильно, но теперьЯ пытаюсь установить / показать ошибки проверки бэкэнда, которые возвращаются с ответом с кодом состояния 400.

Ссылка на документы по методу, который я пытаюсь использовать

Я использую этот метод в методе с именем handle400Error в приведенном ниже коде.

Код My React (и Formik):

import React, { Component } from "react";
import axios from "axios";
import { Formik } from "formik";
import * as Yup from "yup";
import styled from "styled-components";
import FormError from "../formError";

const Label = styled.label``;

class LoginForm extends Component {
  initialValues = {
    password: "",
    username: ""
  };

  getErrorsFromValidationError = validationError => {
    const FIRST_ERROR = 0;
    return validationError.inner.reduce((errors, error) => {
      return {
        ...errors,
        [error.path]: error.errors[FIRST_ERROR]
      };
    }, {});
  };

  getValidationSchema = values => {
    return Yup.object().shape({
      password: Yup.string()
        .min(6, "Password must be at least 6 characters long")
        .required("Password is required!"),
      username: Yup.string()
        .min(5, "Username must be at least 5 characters long")
        .max(40, "Username can not be longer than 40 characters")
        .required("Username is required")
    });
  };

  handleSubmit = async (values, { setErrors }) => {
    console.log("handleSubmit");

    try {
      const response = await axios.post(
        "http://127.0.0.1:8000/rest-auth/login/",
        values
      );
      const loginToken = response.data["key"];
      this.handleLoginSuccess(loginToken);
    } catch (exception) {
      // Expected: 400 status code
      if (exception.response && exception.response.status === 400) {
        // Display server validation errors
        this.handle400Error(exception.response.data, setErrors);
      }
      console.log("exception", exception);
      console.log("exception.response", exception.response);
    }
  };

  handle400Error = (backendErrors, setErrors) => {
    let errors = {};
    for (let key in backendErrors) {
      errors[key] = backendErrors[key][0]; // for now only take the first error of the array
    }
    console.log("errors object", errors);
    setErrors({ errors });
  };

  handleUnexpectedError = () => {};

  handleLoginSuccess = loginToken => {
    console.log("handleLoginSuccess");
    this.props.setGreeneryAppState({
      loginToken: loginToken
    });
    this.props.history.replace(`/${this.props.locale}/`);
  };

  validate = values => {
    const validationSchema = this.getValidationSchema(values);
    try {
      validationSchema.validateSync(values, { abortEarly: false });
      return {};
    } catch (error) {
      return this.getErrorsFromValidationError(error);
    }
  };

  render() {
    return (
      <React.Fragment>
        <h1>Login</h1>
        <Formik
          initialValues={this.initialValues}
          validate={this.validate}
          validationSchema={this.validationSchema}
          onSubmit={this.handleSubmit}
          render={({
            errors,
            touched,
            values,
            handleBlur,
            handleChange,
            handleSubmit
          }) => (
            <form onSubmit={handleSubmit}>
              {errors.non_field_errors && (
                <formError>{errors.non_field_errors}</formError>
              )}
              <Label>Username</Label>
              <input
                onChange={handleChange}
                onBlur={handleBlur}
                value={values.username}
                type="text"
                name="username"
                placeholder="Enter username"
              />
              {touched.username &&
                errors.username && <FormError>{errors.username}</FormError>}
              <Label>Password</Label>
              <input
                onChange={handleChange}
                onBlur={handleBlur}
                value={values.password}
                type="password"
                name="password"
                placeholder="Enter password"
              />
              {touched.password &&
                errors.password && <FormError>{errors.password}</FormError>}
              <button type="submit">Log in</button>
            </form>
          )}
        />
      </React.Fragment>
    );
  }

Ответы [ 2 ]

0 голосов
/ 23 января 2019

Автор Formik здесь ...

setError был устарел в v0.8.0 и переименован в setStatus.Вы можете использовать setErrors(errors) или setStatus(whateverYouWant) в вашей функции handleSubmit, чтобы получить поведение, которое вы хотите здесь, например так:

handleSubmit = async (values, { setErrors, resetForm }) => {
   try {
     // attempt API call
   } catch(e) {
     setErrors(transformMyApiErrors(e))
     // or setStatus(transformMyApiErrors(e))
   }
}

В чем разница использования setStatus против setErrors?

Если вы используете setErrors, ваши ошибки будут стерты следующим вызовом Formik validate или validationSchema, который может быть вызван пользовательским вводом (событие изменения) или размытиемвход (событие размытия).Примечание: предполагается, что вы не установили вручную validateOnChange и validateOnBlur реквизиты в false (по умолчанию они true).

ИМХО setStatus на самом деле идеально здесь, потому что это поместитсообщения об ошибках в отдельной части состояния Formik.Затем вы можете решить, как / когда вы будете показывать это сообщение конечному пользователю следующим образом.

// status can be whatever you want
{!!status && <FormError>{status}</FormError>}
// or mix it up, maybe transform status to mimic errors shape and then ...
{touched.email && (!!errors.email && <FormError>{errors.email}</FormError>) || (!!status && <FormError>{status.email}</FormError>) }

Имейте в виду, что наличие или значение status не влияет на предотвращение следующей отправки формы.Formik прерывает процесс отправки только в случае сбоя проверки .

0 голосов
/ 25 октября 2018

Я только что решил свою собственную проблему.

Мне нужно было использовать:

setErrors( errors )

вместо:

setErrors({ errors })
...