Reactバックエンドとの通信を使用しています。Formik(フォームライブラリ)を適切に実装しようとしています。
主な質問:FormikのsetErrorメソッドを適切に使用するにはどうすればよいですか?
クライアント側の検証エラーは適切に表示されますが、ステータスコード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>
);
}
Formikの著者はこちら...
setError
は 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))
}
}
setStatus
とsetErrors
?の違いは何ですか?
setErrors
を使用すると、エラーはFormikの次の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は、 検証が失敗した場合の送信プロセス のみを中止します。
私は自分の問題を解決しました。
私は使用する必要がありました:
setErrors( errors )
の代わりに:
setErrors({ errors })