Home > Net >  How can I await for an async action dispatch on the click of a button?
How can I await for an async action dispatch on the click of a button?

Time:01-16

I have this react component where in the user wants to send in a login request but whenever I dispatch the action, even before it is executed the further code in my component is executed.

I've tried making the login request function as async and even tried using await before dispatching the action but it's all been in vain.

Component file:

import React from 'react';
import BaseButton from '../BaseButton/BaseButton';
import { useState } from 'react';
import { userLogin } from '../../redux/auth/authActions';
import axios from 'axios';
import {connect} from 'react-redux'

function Login({ isLoggedIn, userLogin }) {
  const [login, setLogin] = useState(true); //to see if the user wats to login or sign up
  const [email, setEmail] = useState("");
  const [name, setName] = useState("");
  const [password, setPassword] = useState("");
  const [confirmPassword, setConfirmPassword] = useState("");

  const handleLogin = () => {
    let userCredentials = {
      email: email,
      password: password
    }
        
    userLogin(userCredentials);   // <------ i want to wait for this to execute before the below code is executed

    if (isLoggedIn) {
      console.log('im here');
    } else {
      console.log('wrong credentials');
    }
  }

  const handleSignUp = async () => {

  }

  return login ? (
    <> 
      {*/ ...some JSX for user input */}

          <div className="flex justify-center">
            <BaseButton variant={'solid'} onClick = {handleLogin}>Submit</BaseButton>
          </div>

      {*/ ...some more JSX for user input */}
    <>
}

const mapStateToProps = (state) => {
  return {
    isLoggedIn: state.auth.isLoggedIn
  }
}

const dispatchStateToProps = (dispatch) => {
  return {
    userLogin: (userCredentials) => dispatch(userLogin(userCredentials))
  }
}

export default connect(mapStateToProps, dispatchStateToProps)(Login);

authActions:

import {
  USER_LOGIN_REQUEST,
  USER_LOGIN_SUCCESS,
  USER_LOGIN_FAILURE,
} from './authTypes';
import axios from 'axios';

export const sendLoginRequest = () => {
  return {
    type: USER_LOGIN_REQUEST,
  };
};

export const loginSucccess = () => {
  return {
    type: USER_LOGIN_SUCCESS,
  };
};

export const loginFailure = (error) => {
  return {
    type: USER_LOGIN_FAILURE,
    payload: error,
  };
};

export const userLogin = (userCredentials) => {
  return (dispatch) => {
    try {
      dispatch(sendLoginRequest());
      axios
        .post('http://localhost:3001/auth/login', userCredentials)
        .then((data) => {
          console.log(data.status);
          dispatch(loginSucccess());
        })
        .catch(err => {
          console.log("incorrect credentials");
          dispatch(loginFailure('incorrect credentials'));
        });
    } catch(err) {
      dispatch(loginFailure(err.message));
    }
  };
};

auth reducer file:

import {
  USER_LOGIN_REQUEST,
  USER_LOGIN_FAILURE,
  USER_LOGIN_SUCCESS,
} from './authTypes';

const initialState = {
  loading: false,
  isLoggedIn: false,
  error: ''
};

const authReducer = (state = initialState, action) => {
  switch (action.type) {
    case USER_LOGIN_REQUEST:
      return {
        ...state,
        loading: true
      }
    case USER_LOGIN_SUCCESS: return{
        ...state,
        loading: false,
        isLoggedIn: true,
    }
    case USER_LOGIN_FAILURE: return{
        ...state,
        loading: false,
        isLoggedIn: false,
        error: action.payload
    }
    default: return state;
  }
};

export default authReducer;

my store file:

import { createStore, applyMiddleware } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import thunk from 'redux-thunk';
import rootReducer from '../rootReducer';

const store = createStore(rootReducer, composeWithDevTools(applyMiddleware(thunk)));

export default store;

root reducer:

import {combineReducers} from 'redux';
import authReducer from './auth/authReducer';

const rootReducer = combineReducers({
  auth: authReducer
});

export default rootReducer;

CodePudding user response:

The userLogin action isn't declared async nor does it return a Promise so this is why your handleLogin handler isn't able to wait for it to complete.

Convert userLogin to an async action function.

export const userLogin = (userCredentials) => async (dispatch) => {
  try {
    dispatch(sendLoginRequest());
    const data = await axios.post('http://localhost:3001/auth/login', userCredentials);

    console.log(data.status);

    dispatch(loginSucccess());

    return true; // <-- return resolved value
  } catch(err) {
    dispatch(loginFailure(err.message));
    return false; // <-- return resolved value
  }
};

Convert handleLogin to an async function so it can await the dispatched action to resolve. Note that handleLogin won't, and can't see any updated isLoggedIn state value from Redux while it has a current value closed over in scope from the time it was called.

const handleLogin = async () => {
  const userCredentials = { email, password };
        
  const authSuccess = await userLogin(userCredentials);

  if (authSuccess) {
    console.log('I'm here');
  } else {
    console.log('wrong credentials');
  }
};

CodePudding user response:

use async await or then catch in handleLogin function and also do not forgot to add return in userLogin and sub functions

`const handleLogin = async () => {
    await userLogin(userCredentials); 
    if(isLoggedIn) {
       console.log('here');
    }
}`

or use then

`userLogin(userCredentials).then(() => { if(isLoggedIn){
          console.log('here');
}});`
  • Related