简体   繁体   English

使用redux-thunk进行异步验证

[英]Async validation with redux-thunk

for my project I am using Redux-Form . 对于我的项目,我正在使用Redux-Form

I want to validate password and automatically log user to system if password is correct. 我想验证密码,如果密码正确,则自动将用户登录到系统。 After user is logged I update some internal redux states. 用户登录后,我更新了一些内部的还原状态。 To do that I used redux thunk with actions method. 为此,我使用了带有动作方法的redux thunk。

Problem that I am facing is that redux thunk action fails to return Promise that is needed for async redux-form validation. 我面临的问题是redux thunk操作无法返回异步redux-form验证所需的Promise。

This is error I have: 这是我有的错误:

asyncValidate function passed to reduxForm must return a promise

Does someone knows where is the problem? 有人知道问题出在哪里吗?

Here is code I am using: 这是我正在使用的代码:

asyncValidate.js asyncValidate.js

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

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


}

export default asyncValidate

User login action 用户登录动作

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);
        })

});

EDIT 1: 编辑1:

Tried code that @Ravindra Ranwala suggested and I still got same error: 尝试了@Ravindra Ranwala建议的代码,但我仍然遇到相同的错误:

@Emrys Myrooin suggested to move code from actions to asyncValidation function but Redux-Form doesn't trigger any error when user (me in this case) enters wrong password. @Emrys Myrooin建议将代码从动作移至asyncValidation函数,但当用户(在本例中为我)输入错误密码时,Redux-Form不会触发任何错误。

Here is code for new asyncValidate function: 这是新的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

EDIT 2. Updated code from comments 编辑2.从注释更新代码

With this code, as soon as password fields triggers blur event I got this error: 使用此代码,一旦密码字段触发模糊事件,我就会收到此错误:

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

After ajax request is finished I got validation error message that I want to have from beginning but password field is not validated... Ajax请求完成后,我从一开始就收到了验证错误消息,但密码字段未验证...

This is error after ajax request is finished: ajax请求完成后,这是错误:

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

asyncValidate function: 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

Reducer actions: 减速器动作:

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

});

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


});

Your function logIn is an action creator that returns an action, here a thunk. 您的函数logIn是一个动作创建者,该动作创建者返回一个动作,此处为一个thunk。 So no, the return of logIn is not a promise. 所以不,返回logIn并不是一个承诺。

I think you should move your async code to the asyncValidate function and use the dispatch given in parameter to dispatch the actions you want to modify the redux state. 我认为您应该将异步代码移至asyncValidate函数,并使用参数中给定的dispatch来分派要修改redux状态的操作。

EDIT 编辑

Your code should look like this : 您的代码应如下所示:

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 })
    })

And in your file ../booker/actions you should have 在文件../booker/actions

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

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

Some explanations: 一些解释:

As pointed by the other answer, you don't have to encapsulate you ajax call into a Promise because axios already return a promise. 就像其他答案指出的那样,您不必将ajax调用封装到Promise因为axios已经返回了promise。 To reject a promise in a then function, you can juste throw an error. 要拒绝then函数中的承诺,您可以抛出一个错误。

An other point is to nether build an action out of the specific action file where you define your actions. 另一点是从定义动作的特定action文件中构建动作。 Otherwise you will have tons a duplicated actions and it's terrible for maintenance. 否则,您将有大量重复的操作,并且维护起来很糟糕。

A last point, you probably never have to explicitly check aBoolean === true in a condition. 最后一点,您可能不必在条件中显式检查aBoolean === true Just do if(aBoolean) ou if(!aBoolean) . 只需执行if(aBoolean)if(!aBoolean) The === can be use if you really want to also check that your variable is actually a boolean (again it's very unusual). 如果确实要检查您的变量是否确实是布尔值(同样非常不寻常),则可以使用===

You don't have to return a promise explicitly. 您不必显式地返回承诺。 thunk becomes useful when you dispatch an action to the store. 当您将操作分派给商店时,thunk变得很有用。 Try changing your code like this. 尝试像这样更改代码。

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
            });
        })
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM