如何使用redux-form和Fetch API 进行服务器端验证?文档中提供了" 提交验证 "演示,其中说服务器端验证的推荐方法是从onSubmit函数返回一个promise.但是我应该把这个承诺放在哪里?据我所知,onSubmit函数应该是我的动作.
this.props.addWidget实际上是我的行动,如下所示.
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将捕获它但是这不起作用.如何使它与示例中的承诺一起工作?
同样从演示中我无法理解this.props.handleSubmit函数应该提供什么.对我来说,演示不解释这一部分.
以下是我根据http://erikras.github.io/redux-form/#/examples/submit-validation上的示例使用fetch的看法.
......但我应该把这个承诺放在哪里? ...应该在this.props.handleSubmit中提供什么?
......但我应该把这个承诺放在哪里?
...应该在this.props.handleSubmit中提供什么?
详情见下面的评论; 抱歉代码块需要一点滚动才能读取:/
components/submitValidation.js
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: // ``, or // b) pass that function to this component as // ``, then // `` 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 ( { // this can be read as "if touched and error, then render div" username.touched && username.error && { username.error } } { password.touched && password.error && { password.error } } { // this is the generic error, passed through as { _error: 'something wrong' } error && { error } } // 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 Log In ); } } // 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 }); }); }); };
如果我错过了某些内容/误解等,请填写评论,我会修改:)