Redux 表单:如何处理表单组件中的错误
Redux forms: how to handle errors in form component
现在我有这样的错误:
Unhandled Rejection (SubmissionError): Submit Validation Failed
27 | .catch(err => {
> 28 | return ErrorHandler.raiseAnError(err);
29 | });
这是我的代码:
TractorForm.js
import React, { Component } from "react";
import PropTypes from "prop-types";
import { reduxForm } from "redux-form";
import FormInput from "../Shared/FormInput";
import GlobalConst from "../GlobalConst";
import { Link } from "react-router-dom";
import SelectInput from "../Shared/SelectInput";
import ErrorHandler from "../ErrorHandler";
const manufacturers = ["DAF", "VOLVO", "SCANIA", "MAN", "IVECO"];
class TractorFormWrapper extends Component {
state = {
loading: false,
isSubmitted: false
};
onFormSubmit = e => {
e.preventDefault();
this.setState({ isSubmitted: true });
if (this.props.valid) {
this.setState({ loading: true });
this.props
.handleSubmit(e)
.then(() => alert("is ok!"))
.catch(err => {
return ErrorHandler.raiseAnError(err);
});
}
};
render() {
const { submitText, error } = this.props;
const { loading, isSubmitted } = this.state;
const formClassNames = loading ? "ui form loading" : "ui form";
return (
<form className={formClassNames} onSubmit={this.onFormSubmit}>
<div className="ui grid fields">
<div className="sixteen wide eight wide computer column">
<SelectInput
name="manufacturer"
type="text"
label="Производитель"
validations={[GlobalConst.REQUIRED]}
isSubmitted={isSubmitted}
values={manufacturers}
/>
</div>
<div className="sixteen wide eight wide computer column">
<FormInput
name="model"
type="text"
label="Модель"
validations={[GlobalConst.REQUIRED]}
isSubmitted={isSubmitted}
/>
</div>
<div className="sixteen wide column">
<FormInput
name="description"
type="textarea"
label="Описание"
isSubmitted={isSubmitted}
/>
</div>
</div>
{error && (
<div className="ui red message">
<strong>{error}</strong>
</div>
)}
<div className="ui fluid buttons">
<button
className="ui primary button"
type="submit"
disabled={loading}
>
{submitText}
</button>
<Link to="/tractors" className="ui button">
Отмена
</Link>
</div>
</form>
);
}
}
let TractorForm = {};
TractorForm.propTypes = {
submitText: PropTypes.string
};
TractorForm.defaultProps = {
submitText: "Отправить"
};
TractorForm = reduxForm({
form: "tractor"
})(TractorFormWrapper);
export default TractorForm;
TractorAdd.js
import React, { Component } from "react";
import TractorForm from "./TractorForm";
import TractorApi from "./TractorApi";
import { toast } from "react-semantic-toasts";
import ErrorHandler from "../ErrorHandler";
class TractorAdd extends Component {
state = {};
submit = values =>
TractorApi.create(values).then(
() => {
toast({
type: "success",
icon: "truck",
title: "Тягач создан",
description: ""
});
this.props.history.push("/tractors");
},
error => {
return Promise.reject(error);
}
);
render() {
return (
<div>
<TractorForm onSubmit={this.submit} submitText="Создать" />
</div>
);
}
}
export default TractorAdd;
ErrorHandler.js
import { SubmissionError } from "redux-form";
export default {
raiseAnError: error => {
if (
error.response.data.hasOwnProperty("message") &&
error.response.data.hasOwnProperty("stackHighlighted")
) {
throw new SubmissionError({
_error: error.response.data.hasOwnProperty("message") || "error"
});
} else {
const errKeys = Object.keys(error.response.data);
const errObj = {};
for (const errItem of errKeys) {
errObj[errItem] = error.response.data[errItem]["message"];
}
errObj["_error"] = "Произошла ошибка!";
throw new SubmissionError(errObj);
}
}
};
为什么我在表单中需要这个而不是添加组件?所以我可以用 loading
状态变量修复逻辑并重新提交表单
还有我的 _error
由于某些原因无法正常工作,但我已经按照文档中的说明完成了所有操作:https://redux-form.com/7.3.0/examples/submitvalidation/
我做错了什么以及如何处理表单组件中的 SubmissionError?
你的错误处理不起作用的原因是你应该在 handleSubmit
函数本身中抛出新的 SubmissionError
,like the example you linked:
<form onSubmit={handleSubmit(submit)}>
function submit(values) {
return sleep(1000).then(() => {
// If error
throw new SubmissionError({
password: 'Wrong password',
_error: 'Login failed!'
})
// The rest logic here ...
})
}
所以你应该稍微重构一下你的代码,像那样(按照评论):
<form className={formClassNames} onSubmit={handleSubmit(values => {
// 1. Your submit logic should be here.
// 2. Better to organize it in a stand-alone function, as `submit` function from the above example.
// 3. If you throw SubmissionError here, the error handling will work.
throw new SubmissionError({
_error: 'Error'
})
)}>
尝试调整和简化您的代码,例如您提供的官方库示例。
更新 1 - 几乎是一个完整的例子。请严格遵守评论:
* 我删除了一些与问题无关的代码块
TractorForm - 它将被重新用于 Edit 和 Add(创建)操作.
class TractorForm extends Component {
render() {
const { handleSubmit, error } = this.props;
return (
<form onSubmit={handleSubmit}>
// Rest input fields should be here ...
{ error && (
<div className="ui red message">
<strong>{error}</strong>
</div>
)}
<div className="ui fluid buttons">
<button
className="ui primary button"
type="submit"
disabled={loading}
>
{submitText}
</button>
</div>
</form>
);
}
}
export default reduxForm({
form: "tractor"
})(TractorForm);
TractorAdd - 用于添加新拖拉机。同样的逻辑,你可以申请Edit Tractor。您必须创建一个新的 TractorEdit
组件,它将 onSubmit
功能传递给 TractorForm
。
class TractorAdd extends Component {
onSubmit (values) {
// Please make sure here you return the promise result. It's a `redux-form` gotcha.
// If you don't return it, error handling won't work.
return TractorApi.create(values).then(
() => {
toast({
type: "success",
icon: "truck",
title: "Тягач создан",
description: ""
});
this.props.history.push("/tractors");
},
error => {
// 1. Here you should throw new SubmissionError.
// 2. You should normalize the error, using some parts of `ErrorHandler` function
throw new SubmissionError(error)
}
);
}
render() {
return <div>
<TractorForm onSubmit={this.onSubmit} submitText="Создать" />
</div>
}
}
export default TractorAdd;
更新 2 - 保持原样执行,但稍微更改 TractorFormWrapper
onFormSubmit
及其用法:
文档说明here。
拖拉机形式
class TractorFormWrapper extends Component {
state = {
loading: false,
isSubmitted: false
};
onFormSubmit = data => {
this.setState({ isSubmitted: true });
if (this.props.valid) {
this.setState({ loading: true });
// `onSubmit` comes from `TractorAdd`
return this.props.onSubmit(data)
.then(() => alert("is ok!"))
.catch(err => {
return ErrorHandler.raiseAnError(err);
});
}
};
render() {
const { handleSubmit } = this.props
return <form onSubmit={handleSubmit(this.onFormSubmit)}>The rest logic is here ...</form>
}
}
let TractorForm = {};
TractorForm.propTypes = {
submitText: PropTypes.string
};
TractorForm.defaultProps = {
submitText: "Отправить"
};
TractorForm = reduxForm({
form: "tractor"
})(TractorFormWrapper);
export default TractorForm;
现在我有这样的错误:
Unhandled Rejection (SubmissionError): Submit Validation Failed
27 | .catch(err => {
> 28 | return ErrorHandler.raiseAnError(err);
29 | });
这是我的代码:
TractorForm.js
import React, { Component } from "react";
import PropTypes from "prop-types";
import { reduxForm } from "redux-form";
import FormInput from "../Shared/FormInput";
import GlobalConst from "../GlobalConst";
import { Link } from "react-router-dom";
import SelectInput from "../Shared/SelectInput";
import ErrorHandler from "../ErrorHandler";
const manufacturers = ["DAF", "VOLVO", "SCANIA", "MAN", "IVECO"];
class TractorFormWrapper extends Component {
state = {
loading: false,
isSubmitted: false
};
onFormSubmit = e => {
e.preventDefault();
this.setState({ isSubmitted: true });
if (this.props.valid) {
this.setState({ loading: true });
this.props
.handleSubmit(e)
.then(() => alert("is ok!"))
.catch(err => {
return ErrorHandler.raiseAnError(err);
});
}
};
render() {
const { submitText, error } = this.props;
const { loading, isSubmitted } = this.state;
const formClassNames = loading ? "ui form loading" : "ui form";
return (
<form className={formClassNames} onSubmit={this.onFormSubmit}>
<div className="ui grid fields">
<div className="sixteen wide eight wide computer column">
<SelectInput
name="manufacturer"
type="text"
label="Производитель"
validations={[GlobalConst.REQUIRED]}
isSubmitted={isSubmitted}
values={manufacturers}
/>
</div>
<div className="sixteen wide eight wide computer column">
<FormInput
name="model"
type="text"
label="Модель"
validations={[GlobalConst.REQUIRED]}
isSubmitted={isSubmitted}
/>
</div>
<div className="sixteen wide column">
<FormInput
name="description"
type="textarea"
label="Описание"
isSubmitted={isSubmitted}
/>
</div>
</div>
{error && (
<div className="ui red message">
<strong>{error}</strong>
</div>
)}
<div className="ui fluid buttons">
<button
className="ui primary button"
type="submit"
disabled={loading}
>
{submitText}
</button>
<Link to="/tractors" className="ui button">
Отмена
</Link>
</div>
</form>
);
}
}
let TractorForm = {};
TractorForm.propTypes = {
submitText: PropTypes.string
};
TractorForm.defaultProps = {
submitText: "Отправить"
};
TractorForm = reduxForm({
form: "tractor"
})(TractorFormWrapper);
export default TractorForm;
TractorAdd.js
import React, { Component } from "react";
import TractorForm from "./TractorForm";
import TractorApi from "./TractorApi";
import { toast } from "react-semantic-toasts";
import ErrorHandler from "../ErrorHandler";
class TractorAdd extends Component {
state = {};
submit = values =>
TractorApi.create(values).then(
() => {
toast({
type: "success",
icon: "truck",
title: "Тягач создан",
description: ""
});
this.props.history.push("/tractors");
},
error => {
return Promise.reject(error);
}
);
render() {
return (
<div>
<TractorForm onSubmit={this.submit} submitText="Создать" />
</div>
);
}
}
export default TractorAdd;
ErrorHandler.js
import { SubmissionError } from "redux-form";
export default {
raiseAnError: error => {
if (
error.response.data.hasOwnProperty("message") &&
error.response.data.hasOwnProperty("stackHighlighted")
) {
throw new SubmissionError({
_error: error.response.data.hasOwnProperty("message") || "error"
});
} else {
const errKeys = Object.keys(error.response.data);
const errObj = {};
for (const errItem of errKeys) {
errObj[errItem] = error.response.data[errItem]["message"];
}
errObj["_error"] = "Произошла ошибка!";
throw new SubmissionError(errObj);
}
}
};
为什么我在表单中需要这个而不是添加组件?所以我可以用 loading
状态变量修复逻辑并重新提交表单
还有我的 _error
由于某些原因无法正常工作,但我已经按照文档中的说明完成了所有操作:https://redux-form.com/7.3.0/examples/submitvalidation/
我做错了什么以及如何处理表单组件中的 SubmissionError?
你的错误处理不起作用的原因是你应该在 handleSubmit
函数本身中抛出新的 SubmissionError
,like the example you linked:
<form onSubmit={handleSubmit(submit)}>
function submit(values) {
return sleep(1000).then(() => {
// If error
throw new SubmissionError({
password: 'Wrong password',
_error: 'Login failed!'
})
// The rest logic here ...
})
}
所以你应该稍微重构一下你的代码,像那样(按照评论):
<form className={formClassNames} onSubmit={handleSubmit(values => {
// 1. Your submit logic should be here.
// 2. Better to organize it in a stand-alone function, as `submit` function from the above example.
// 3. If you throw SubmissionError here, the error handling will work.
throw new SubmissionError({
_error: 'Error'
})
)}>
尝试调整和简化您的代码,例如您提供的官方库示例。
更新 1 - 几乎是一个完整的例子。请严格遵守评论:
* 我删除了一些与问题无关的代码块
TractorForm - 它将被重新用于 Edit 和 Add(创建)操作.
class TractorForm extends Component {
render() {
const { handleSubmit, error } = this.props;
return (
<form onSubmit={handleSubmit}>
// Rest input fields should be here ...
{ error && (
<div className="ui red message">
<strong>{error}</strong>
</div>
)}
<div className="ui fluid buttons">
<button
className="ui primary button"
type="submit"
disabled={loading}
>
{submitText}
</button>
</div>
</form>
);
}
}
export default reduxForm({
form: "tractor"
})(TractorForm);
TractorAdd - 用于添加新拖拉机。同样的逻辑,你可以申请Edit Tractor。您必须创建一个新的 TractorEdit
组件,它将 onSubmit
功能传递给 TractorForm
。
class TractorAdd extends Component {
onSubmit (values) {
// Please make sure here you return the promise result. It's a `redux-form` gotcha.
// If you don't return it, error handling won't work.
return TractorApi.create(values).then(
() => {
toast({
type: "success",
icon: "truck",
title: "Тягач создан",
description: ""
});
this.props.history.push("/tractors");
},
error => {
// 1. Here you should throw new SubmissionError.
// 2. You should normalize the error, using some parts of `ErrorHandler` function
throw new SubmissionError(error)
}
);
}
render() {
return <div>
<TractorForm onSubmit={this.onSubmit} submitText="Создать" />
</div>
}
}
export default TractorAdd;
更新 2 - 保持原样执行,但稍微更改 TractorFormWrapper
onFormSubmit
及其用法:
文档说明here。
拖拉机形式
class TractorFormWrapper extends Component {
state = {
loading: false,
isSubmitted: false
};
onFormSubmit = data => {
this.setState({ isSubmitted: true });
if (this.props.valid) {
this.setState({ loading: true });
// `onSubmit` comes from `TractorAdd`
return this.props.onSubmit(data)
.then(() => alert("is ok!"))
.catch(err => {
return ErrorHandler.raiseAnError(err);
});
}
};
render() {
const { handleSubmit } = this.props
return <form onSubmit={handleSubmit(this.onFormSubmit)}>The rest logic is here ...</form>
}
}
let TractorForm = {};
TractorForm.propTypes = {
submitText: PropTypes.string
};
TractorForm.defaultProps = {
submitText: "Отправить"
};
TractorForm = reduxForm({
form: "tractor"
})(TractorFormWrapper);
export default TractorForm;