首页 文章

使用redux-form和Fetch API进行服务器验证

提问于
浏览
14

如何使用redux-form和Fetch API进行服务器端验证?文档中提供了“Submit Validation”演示,其中说服务器端验证的推荐方法是从onSubmit函数返回一个promise . 但是我应该把这个承诺放在哪里?据我所知,onSubmit函数应该是我的动作 .

<form onSubmit={this.props.addWidget}>...

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将捕获它但是这不起作用 . 如何使它与example的承诺一起工作?

同样从演示中我无法理解this.props.handleSubmit函数应该提供什么 . 对我来说,演示不解释这一部分 .

2 回答

  • 1

    这是我在http://erikras.github.io/redux-form/#/examples/submit-validation上根据示例使用fetch的看法 .

    ...但我应该在哪里放置这个承诺? ...应该在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: 
        //   `<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 });
          });
      });
    };
    

    如果我错过了某些内容/误解等,请填写评论,我会修改:)

  • 20

    原来,there are undocumented property returnRejectedSubmitPromise 必须设置为true .

相关问题