【问题标题】:Async validation with redux-thunk使用 redux-thunk 进行异步验证
【发布时间】:2018-01-10 17:16:50
【问题描述】:

对于我的项目,我使用的是Redux-Form

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

我面临的问题是 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. 来自 cmets 的更新代码

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

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


});

【问题讨论】:

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


    【解决方案1】:

    您不必明确返回承诺。当您向商店发送操作时,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
                });
            })
        }
    }
    

    【讨论】:

    • 嗨。我尝试了您的代码,但仍然存在相同的错误。问题是异步函数不会“等待” axios 调用完成
    • 你的异步函数是什么?
    • 您可以在我帖子中的原始 asyncValidate.js 中看到它。我将 logIn 函数导入 asyncValidate 函数,然后从那里调用函数。
    • 我们不需要处理解析,或者明确拒绝。我更新了答案。你现在可以试试吗?
    • 我试过了,错误还是一样。问题是在ajax请求完成之前函数存在
    【解决方案2】:

    您的函数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)if(!aBoolean)=== 如果你真的想检查你的变量是否实际上是一个布尔值(这也是非常不寻常的),可以使用。

    【讨论】:

    • 我将 logIn 函数移至 asyncValidate 函数,但由于某种原因验证未触发。 Ajax 调用执行但没有验证错误(我输入了错误的密码)
    • @jureispro 更新了答案
    • 感谢您的宝贵时间和帮助。我用你的代码更新了我的代码,但我仍然遇到同样的错误。在密码字段异步函数上的模糊事件不会“等待”ajax 请求完成后,我收到错误“不承诺”错误。 Ajax 请求被触发,请求完成后我得到了我没有处理承诺错误的承诺错误。您可以在编辑第 2 段检查代码
    • @jureispro 抱歉弄错了...您必须删除 asyncValidate 的括号或添加退货声明。检查我的答案,我已经更新了。
    • 感谢您的帮助。我试过你的代码,现在我没有任何控制台错误。我唯一的问题是密码字段不会将原始状态更改为无效状态。即使密码错误,模糊字段也有效后,当我在控制台中调试时,我可以看到抛出的错误
    猜你喜欢
    • 2018-01-02
    • 1970-01-01
    • 2019-03-02
    • 2018-01-31
    • 1970-01-01
    • 2020-10-28
    • 2016-12-20
    • 2020-05-16
    • 2017-03-03
    相关资源
    最近更新 更多