Redux store cannot update

Viewed 43

I have a button trigger project create. What I want to do is when I click button, it will create a new project, and if there is no issue with product, it will go to the next step.

The dispatch on the click handler is working, I can see the redux runs the faild reducer if there is error, but the projectData.successStatus inside the handler cannot get the latest value which the the successStatus I want it to be false. It's still the previsous retrive project list success Status. So the nextStep() condition is not working.

Can someone help me find what's wrong?

This is the handler button:

const handleNextButton = useCallback(() => {
    if (newProjectName) {
        const newProjectWithProjectName = {
            ...newProject,
            projectName: newProjectName,
        }
        dispatch(createNewProjectReq(newProjectWithProjectName)) // create new project
        if (projectData.successStatus) {
            nextStep()
        }
    }
}, [newProjectName, projectData])

On the action, I have request, add, fail:

export const createNewProjectReq = (newProject) => async (dispatch) => {
    dispatch({ type: PROJECT_SENDING_REQUEST })
    try {
        const result = await createNewProject(newProject)
        const { project, message } = result.data.data
        dispatch({
            type: PROJECT_LIST_ADD,
            payload: { project, message },
        })
    } catch (error) {
        dispatch({ type: PROJECT_REQUEST_FAIL, payload: error.data.message })
    }
}

Reducer switch:

switch (action.type) {
    case PROJECT_SENDING_REQUEST:
        console.log("PROJECT_SENDING_REQUEST")
        return {
            ...state,
            loading: true,
            successStatus: false,
        }
    case PROJECT_LIST_SUCCESS:
        console.log("PROJECT_LIST_SUCCESS")
        return {
            loading: false,
            projects: action.payload.projectListGroupByProjectId,
            successStatus: true,
            message: action.payload.message,
        }
    case PROJECT_LIST_ADD:
        console.log("PROJECT_LIST_ADD")
        return {
            ...state,
            loading: false,
            projects: [...state.projects, action.payload.project],
            successStatus: true,
            message: action.payload.message,
        }
    case PROJECT_REQUEST_FAIL: {
        console.log("PROJECT_REQUEST_FAIL")
        return {
            ...state,
            loading: false,
            successStatus: false,
            message: action.payload,
        }
    }
    default:
        return state
}
1 Answers

Issues

  1. handleNextButton callback is synchronous code.
  2. Reducer functions are also synchronous code.
  3. State is generally considered const during a render cycle, i.e. it won't ever change in the middle of a render cycle or synchronous code execution.

Because of these reason the projectData state will not have been updated yet, the conditional check happens before the actions are processed.

Solution

Since you really are just interested in the success of the action so you can go to the next step you can return a boolean value from the asynchronous action and await it or Promise-chain from it.

export const createNewProjectReq = (newProject) => async (dispatch) => {
  dispatch({ type: PROJECT_SENDING_REQUEST });
  try {
    const result = await createNewProject(newProject);
    const { project, message } = result.data.data;
    dispatch({
      type: PROJECT_LIST_ADD,
      payload: { project, message },
    });
    return true; // <-- success status
  } catch (error) {
    dispatch({ type: PROJECT_REQUEST_FAIL, payload: error.data.message });
    return false; // <-- failure status
  }
}

...

const handleNextButton = useCallback(() => {
  if (newProjectName) {
    const newProjectWithProjectName = {
      ...newProject,
      projectName: newProjectName,
    }
    dispatch(createNewProjectReq(newProjectWithProjectName))
      .then(success => {
        if (success) {
          nextStep();
        }
      });
  }
}, [newProjectName, projectData]);

Demo

Simple demo with click handler calling asynchronous function with 50% chance to succeed/fail.

Edit redux-store-cannot-update

Related