使用redux-thunk进行异步验证

时间:2017-08-03 08:12:17

标签: reactjs redux react-redux redux-form redux-thunk

我的项目我正在使用Redux-Form

如果密码正确,我想验证密码并自动将用户登录到系统。用户登录后,我更新了一些内部redux状态。为此,我使用了redux thunk和actions方法。

我面临的问题是redux thunk操作无法返回异步redux-form验证所需的Promise。

这是我的错误:

asyncValidate function passed to reduxForm must return a promise

有人知道问题出在哪里吗?

以下是我正在使用的代码:

asyncValidate.js

import {logIn} from '../user/actions';

const asyncValidate = (values, dispatch) => {
    return logIn(values.booker.email, values.booker.password);


}

export default asyncValidate

用户登录操作

export const logIn = (email, password) => (dispatch) =>
new Promise(function (resolve, reject) {
    axios.post('/login_check', qs.stringify({
        _username: email,
        _password: password,
        _csrf_token: CSRF_TOKEN
    }), ajaxConfig)
        .then(response => {
            if (response.data.success !== true) {

                dispatch({
                    type: LOG_IN_ERROR,
                    payload: response.data.message
                });
                reject(response.data.message);

            }
            else {
                dispatch({
                    type: LOG_IN_SUCCESS,
                    payload: response.data.user
                });
                resolve();
            }

        })
        .catch((error) => {
            dispatch({
                type: LOG_IN_ERROR,
                payload: error
            });
            reject(error);
        })

});

编辑1:

尝试了@Ravindra Ranwala建议的代码,我仍然遇到同样的错误:

@Emrys Myrooin建议将代码从操作移动到asyncValidation函数,但当用户(在本例中为我)输入错误的密码时,Redux-Form不会触发任何错误。

以下是新的asyncValidate函数的代码:

import {LOG_IN_ERROR, LOG_IN_SUCCESS, CSRF_TOKEN} from '../booker/actions';
    import axios from 'axios';
    const qs = require('qs');
    const ajaxConfig = {
        headers: {"X-Requested-With": "XMLHttpRequest"}
    };

const asyncValidate = (values, dispatch) => {
    console.log(values);
    return new Promise(function (resolve, reject) {
        axios.post('/login_check', qs.stringify({
        _username: values.booker.email,
        _password: values.booker.password,
        _csrf_token: CSRF_TOKEN
    }), ajaxConfig)
        .then(response => {
            console.log(response);
            if (response.data.success !== true) {

                dispatch({
                    type: LOG_IN_ERROR,
                    payload: response.data.message
                });
                reject(response.data.message);

            }
            else {
                dispatch({
                    type: LOG_IN_SUCCESS,
                    payload: response.data.user
                });
                resolve();
            }

        })
        .catch((error) => {
            dispatch({
                type: LOG_IN_ERROR,
                payload: error
            });
            reject(error);
        })
    })


    }

    export default asyncValidate

编辑2.更新了评论中的代码

使用此代码,只要密码字段触发模糊事件,我就会收到此错误:

Uncaught Error: asyncValidate function passed to reduxForm must return a promise

ajax请求完成后,我收到了验证错误消息,我想从头开始但密码字段未经过验证...

ajax请求完成后出现错误:

asyncValidate.js?9b4c:19 Uncaught (in promise) Error: Bad credentials.

asyncValidate函数:

import {logInError, logInSuccess, CSRF_TOKEN} from '../booker/actions';

import axios from 'axios'
const qs = require('qs')
const ajaxConfig = {
    headers: { 'X-Requested-With': 'XMLHttpRequest' },
}

const asyncValidate = (values, dispatch) => {
    axios
        .post(
            '/login_check', qs.stringify({
                _username: values.booker.email,
                _password: values.booker.password,
                _csrf_token: CSRF_TOKEN,
            }), ajaxConfig)
        .then(response => {
            console.log(response);
            if (response.data.success)
                dispatch(logInSuccess(response.data.user))
            else
                throw new Error(response.data.message)
        })
        .catch(error => {
            dispatch(logInError(error.message))
            throw error
        })
}

export default asyncValidate

减速器动作:

export const logInSuccess = response => ({
    type: LOG_IN_SUCCESS,
    payload: response

});

export const logInError = (response) => ({
    type: LOG_IN_ERROR,
    payload: response


});

2 个答案:

答案 0 :(得分:0)

你的函数logIn是一个动作创建者,它返回一个动作,这里是一个thunk。所以不,logIn的回归不是承诺。

我认为您应该将异步代码移动到asyncValidate函数,并使用参数中给出的dispatch来分派您想要修改redux状态的操作。

修改

您的代码应如下所示:

import { logInError, logInSuccess, CSRF_TOKEN } from '../booker/actions'
import axios from 'axios'
const qs = require('qs')
const ajaxConfig = {
  headers: { 'X-Requested-With': 'XMLHttpRequest' },
}

const asyncValidate = (values, dispatch) => 
  axios
    .post(
      '/login_check', qs.stringify({
        _username: values.booker.email,
        _password: values.booker.password,
        _csrf_token: CSRF_TOKEN,
      }), ajaxConfig)
    .then(response => {
      if (response.data.success)
        dispatch(logInSuccess(response.data.user))
      else
        throw new Error(response.data.message)
    })
    .catch(error => {
      dispatch(logInError(error.message))
      throw { password: error.message })
    })

在您的文件../booker/actions中,您应该

export const logInSuccess = user => ({
  type: LOG_IN_ERROR,
  payload: user
})

export const logInError = (message) => ({
  type: LOG_IN_ERROR,
  payload: message
})

一些解释:

正如另一个答案所指出的,您不必将ajax调用封装到Promise中,因为axios已经返回了一个承诺。要拒绝then函数中的承诺,您可以抛出错误。

另一点是,在您定义操作的特定action文件中构建一个操作。否则你将会遇到重复的操作,而且维护起来很糟糕。

最后一点,您可能永远不必在条件中明确检查aBoolean === true。只需if(aBoolean) ou if(!aBoolean)即可。如果你真的想要检查你的变量实际上是一个布尔值(同样它非常不寻常),可以使用===

答案 1 :(得分:0)

您不必明确返回承诺。当您向商店发送操作时,thunk变得有用。尝试更改这样的代码。

export function login(email, password) {
    return function(dispatch) {
        axios.post('/login_check', qs.stringify({
        _username: email,
        _password: password,
        _csrf_token: CSRF_TOKEN
    }), ajaxConfig)
        .then(response => {
            if (response.data.success !== true) {

                dispatch({
                    type: LOG_IN_ERROR,
                    payload: response.data.message
                });

            }
            else {
                dispatch({
                    type: LOG_IN_SUCCESS,
                    payload: response.data.user
                });
            }

        })
        .catch((error) => {
            dispatch({
                type: LOG_IN_ERROR,
                payload: error
            });
        })
    }
}