Async await is not functioning properly on my React project. It is not awaiting a response. Redux state displaying the previous or default value while calling the function but outside the function, it's working fine. As you can see, I print the employee from the selector in the handleSubmit function, however this prints the prior or default state, and I need the updated value to proceed. Data is not being awaited.
// handle submit function
const handleSubmit = async(values) => {
const personalData = new FormData();
Object.keys(personalValue).forEach((key) => personalData.append(key, personalValue[key]));
await dispatch(addEmployeePersonal(personalData));
console.log(employee) // Inside the function Employee prints default or previous state value
};
console.log(employee) // Here it's working fine, Outside the function employee prints updated value
// Selector
const {
employee,
employeeLoading,
employeeError
} = useSelector((state) => state.employee);
// Redux Reducer
export const employeeReducer = (state = {
employee: 0
}, action) => {
switch (action.type) {
case UPDATE_EMPLOYEE_PERSONAL_REQUEST:
case EMPLOYEE_ID_REQUEST:
case NEW_EMPLOYEE_PERSONAL_REQUEST:
case NEW_EMPLOYEE_OFFICIAL_REQUEST:
case DELETE_EMPLOYEE_REQUEST:
return {
...state,
employeeLoading: true,
employee: 0,
};
case UPDATE_EMPLOYEE_PERSONAL_SUCCESS:
case UPDATE_EMPLOYEE_OFFICIAL_SUCCESS:
case EMPLOYEE_ID_SUCCESS:
case NEW_EMPLOYEE_PERSONAL_SUCCESS:
case NEW_EMPLOYEE_OFFICIAL_SUCCESS:
case DELETE_EMPLOYEE_SUCCESS:
return {
...state,
employeeLoading: false,
employee: action.payload,
};
case UPDATE_EMPLOYEE_PERSONAL_FAILED:
case UPDATE_EMPLOYEE_OFFICIAL_FAILED:
case EMPLOYEE_ID_FAILED:
case NEW_EMPLOYEE_PERSONAL_FAILED:
case NEW_EMPLOYEE_OFFICIAL_FAILED:
case DELETE_EMPLOYEE_FAILED:
return {
...state,
employeeLoading: false,
employeeError: action.payload,
};
case CLEAR_ERRORS:
return {
...state,
employeeError: null,
};
default:
return state;
}
};
// Redux Action
export const addEmployeePersonal = (info) => async(dispatch) => {
try {
dispatch({
type: NEW_EMPLOYEE_PERSONAL_REQUEST
});
const {
data
} = await coreAxios.post("/api/Employee/PersonalInfo", info);
dispatch({
type: NEW_EMPLOYEE_PERSONAL_SUCCESS,
payload: data,
});
} catch (error) {
dispatch({
type: NEW_EMPLOYEE_PERSONAL_FAILED,
payload: error.response,
});
}
};
Reason: At the first render of the component, the value employee
is 0
. You trigger the form submit handler, it uses the employee
, which value is 0
. Even though you dispatch an action and try to change it, the handleSubmit
still uses the employee
evaluated in the first render(execution of function component) of the component before finishing executing. await dispatch(thunk())
will NOT wait for next render of the component. That's why you get the previous value of employee
.
After handleSubmit
finishes its execution, the state in the redux store has been changed, the redux store context provider will subscribe to that change and rerender the children. Your component will re-render(the second execution of the function component), useSelector
will execute again and return the new employee
. A new handleSubmit
function will be declared and it reference the new employee
defined in the function component scope.
There are two solutions:
Option 1: useEffect
useEffect(() => {
// get the latest employee to do something.
}, [employee])
Option 2: return action payload in thunk so that you can get it after dispatching action
export const addEmployeePersonal = (info) => async(dispatch) => {
try {
dispatch({
type: NEW_EMPLOYEE_PERSONAL_REQUEST
});
const {
data
} = await coreAxios.post("/api/Employee/PersonalInfo", info);
dispatch({
type: NEW_EMPLOYEE_PERSONAL_SUCCESS,
payload: data,
});
return data; // here
} catch (error) {
dispatch({
type: NEW_EMPLOYEE_PERSONAL_FAILED,
payload: error.response,
});
}
};
const handleSubmit = async(values) => {
const personalData = new FormData();
Object.keys(personalValue).forEach((key) => personalData.append(key, personalValue[key]));
const newEmployee = await dispatch(addEmployeePersonal(personalData));
// Do something with newEmployee.
};