我正在使用React与后端通信。现在尝试正确实现Formik(表单库)。
主要问题: 如何正确使用Formik的setError方法?
客户端验证错误可以正确显示,但是现在我尝试设置/显示后端验证错误,这些错误将通过状态码400的响应返回。
链接到我尝试使用的方法的文档
我在下面的代码中名为 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> ); }
Formik作者在这里…
setError在v0.8.0中已弃用,并重命名为setStatus。您可以使用setErrors(errors)或setStatus(whateverYouWant)在handleSubmit函数中获得所需的行为,如下所示:
setError
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 vs.有setErrors什么区别?
setErrors
如果您使用setErrors,您的错误将被Formik的下一个validate或validationSchema调用清除,这些错误可以由用户键入(更改事件)或模糊输入(模糊事件)触发。注意:这是假设您尚未手动设置validateOnChange和设置validateOnBlur道具false(它们是true默认设置)。
validate
validationSchema
validateOnChange
validateOnBlur
false
true
IMHO 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仅中止提交过程。
status