使用 redux-form 和 Fetch API 进行服务器验证 [英] Make server validation using redux-form and Fetch API
问题描述
如何使用 redux-form 和 Fetch API 进行服务器端验证?文档中提供了提交验证"演示,说明进行服务器端验证的推荐方法是从 onSubmit 函数返回一个承诺.但是我应该把那个承诺放在哪里呢?据我了解,onSubmit 函数应该是我的操作.
How to make server-side validation using redux-form and Fetch API? There are "Submit Validation" demo provided in the docs which says that recommended way to do server side validation is to return a promise from the onSubmit function. But where should I place that promise? As I understood onSubmit function should be my action.
<form onSubmit={this.props.addWidget}>...
this.props.addWidget 实际上是我的操作,下面提供.
Where this.props.addWidget is actually my action, provided below.
import fetch from 'isomorphic-fetch';
...
function fetchAddWidget(widget, workspace) {
return dispatch => {
dispatch(requestAddWidget(widget, workspace));
return fetch.post(`/service/workspace/${workspace}/widget`, widget)
.then(parseJSON)
.then(json => {
dispatch(successAddWidget(json, workspace));
DataManager.handleSubscribes(json);
})
.catch(error => popupErrorMessages(error));
}
}
export function addWidget(data, workspace) {
return (dispatch, getState) => {
return dispatch(fetchAddWidget(data, workspace));
}
}
如您所见,我使用 fetch API.我希望 fetch 会返回 promise 并且 redux-form 会捕获它,但这不起作用.如何使它与 example 的承诺一起工作?
As you see I use fetch API. I expected that fetch will return promise and redux-form will catch it but that doesn't work. How to make it work with promise from example?
同样从演示中我无法理解 this.props.handleSubmit 函数中应该提供什么.Demo不解释这部分,至于我.
Also from the demo I can not understand what should be provided in this.props.handleSubmit function. Demo does not explain this part, as for me.
推荐答案
以下是我根据 http://erikras.github.io/redux-form/#/examples/submit-validation.
- ...但是我应该把那个承诺放在哪里?
- ...this.props.handleSubmit 中应该提供什么?
详情见下方评论;抱歉,代码块需要一点滚动才能阅读:/
The detail is in the comments below; sorry that the code blocks require a bit of scrolling to read :/
import React, { Component, PropTypes } from 'react';
import { reduxForm } from 'redux-form';
import { myHandleSubmit, show as showResults } from '../redux/modules/submission';
class SubmitValidationForm extends Component {
// the following three props are all provided by the reduxForm() wrapper / decorator
static propTypes = {
// the field names we passed in the wrapper;
// each field is now an object with properties:
// value, error, touched, dirty, etc
// and methods onFocus, onBlur, etc
fields: PropTypes.object.isRequired,
// handleSubmit is _how_ to handle submission:
// eg, preventDefault, validate, etc
// not _what_ constitutes or follows success or fail.. that's up to us
// I must pass a submit function to this form, but I can either:
// a) import or define a function in this component (see above), then:
// `<form onSubmit={ this.props.handleSubmit(myHandleSubmit) }>`, or
// b) pass that function to this component as
// `<SubmitValidationForm onSubmit={ myHandleSubmit } etc />`, then
// `<form onSubmit={this.props.handleSubmit}>`
handleSubmit: PropTypes.func.isRequired,
// redux-form listens for `reject({_error: 'my error'})`, we receive `this.props.error`
error: PropTypes.string
};
render() {
const { fields: { username, password }, error, handleSubmit } = this.props;
return (
<form onSubmit={ handleSubmit(myHandleSubmit) }>
<input type="text" {...username} />
{
// this can be read as "if touched and error, then render div"
username.touched && username.error && <div className="form-error">{ username.error }</div>
}
<input type="password" {...password} />
{ password.touched && password.error && <div className="form-error">{ password.error }</div> }
{
// this is the generic error, passed through as { _error: 'something wrong' }
error && <div className="text-center text-danger">{ error }</div>
}
// not sure why in the example @erikras uses
// `onClick={ handleSubmit }` here.. I suspect a typo.
// because I'm using `type="submit"` this button will trigger onSubmit
<button type="submit">Log In</button>
</form>
);
}
}
// this is the Higher Order Component I've been referring to
// as the wrapper, and it may also be written as a @decorator
export default reduxForm({
form: 'submitValidation',
fields: ['username', 'password'] // we send only field names here
})(SubmitValidationForm);
<小时>
../redux/modules/submission.js
// (assume appropriate imports)
function postToApi(values) {
return fetch( API_ENDPOINT, {
credentials: 'include',
mode: 'cors',
method: 'post',
body: JSON.stringify({values}),
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': CSRF_TOKEN
}
}).then( response => Promise.all([ response, response.json()] ));
}
export const myHandleSubmit = (values, dispatch) => {
dispatch(startLoading());
return new Promise((resolve, reject) => {
// postToApi is a wrapper around fetch
postToApi(values)
.then(([ response, json ]) => {
dispatch(stopLoading());
// your statuses may be different, I only care about 202 and 400
if (response.status === 202) {
dispatch(showResults(values));
resolve();
}
else if (response.status === 400) {
// here I expect that the server will return the shape:
// {
// username: 'User does not exist',
// password: 'Wrong password',
// _error: 'Login failed!'
// }
reject(json.errors);
}
else {
// we're not sure what happened, but handle it:
// our Error will get passed straight to `.catch()`
throw(new Error('Something went horribly wrong!'));
}
})
.catch( error => {
// Otherwise unhandled server error
dispatch(stopLoading());
reject({ _error: error });
});
});
};
<小时>
如果我遗漏了什么/误解等,请发表评论,我会修改:)
Please chime in with comments if I've missed something / misinterpreted, etc, and I'll amend :)
这篇关于使用 redux-form 和 Fetch API 进行服务器验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!