我正在使用React与后端进行通信.现在正在try 正确地实现Formik(表单库).

主要问题:

客户端验证错误正确显示,但现在我正在try 设置/显示后端验证错误,返回的响应状态代码为400.

Link到我try 使用的方法的文档

我在下面代码中名为handle400Error的方法中使用这个方法.

我的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>
    );
  }

推荐答案

福米克的作者在这里...

setErrordeprecated in v0.8.0,改名为setStatus.您可以在handleSubmit函数中使用setErrors(errors)setStatus(whateverYouWant)来获得您想要的行为,如下所示:

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

What's the difference use 100 vs. 101?

如果您使用setErrors,您的错误将被Formik的下一个validatevalidationSchema调用消除,该调用可由用户键入(更改事件)或模糊输入(模糊事件)触发.注意:假设您没有手动将validateOnChangevalidateOnBlurprops 设置为false(默认为true).

IMHO setStatus在这里非常理想,因为它将把错误消息放在Formik state的一个单独部分.然后,您可以决定如何/何时向最终用户显示此消息.

// 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只会中止submission process if validation fails次.

Reactjs相关问答推荐

从`redux—thunk`导入thunk `在stackblitz中不起作用

关于同一位置的不同组件实例的react S规则被视为相同组件

Antd V5组件自定义主题

在React中使用映射创建flex组件

React 错误: 只能用作 元素的子元素,从不直接渲染.请将您的 包裹在

如何在使用 React Router v6 将当前页面的状态传递给上一页的同时导航到上一页?

在按钮单击中将动态参数传递给 React Query

在 React 的父级中多次调用子级时从子级获取数据到父级

作为单个变量的 React 组件是否比 memoized 组件渲染得更快?

React Final Form - 单选按钮在 FieldArray 中不起作用

React 中的 Slide API Mui 在开始而不是结束时触发侦听器

setState 改变对象引用

如果查询不存在,如何返回所有产品?

如何在 Reactjs 中判断受保护路由上的用户角色?

当页面重新加载react 路由导航到第一页 v6

仅在重新渲染后设置状态

服务器端分页未按预期工作

ClearInterval 在 React 中的 useRef 没有按预期工作

React 似乎在触发另一个组件时重新渲染了错误的组件

如何在按钮左下角制作 Material UI 菜单下拉菜单