Hi I have an issue with redux/saga/promises - Not entirely sure where the issue is:

//USER SERVICE
function login(username, password) {
  const requestOptions = {
    method: "POST",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    body:
      "username=" + username + "&password=" + password + "&grant_type=password"
  };

  return fetch(`${Config.apiUrl}/Token`, requestOptions)
    .then(handleLoginResponse)
    .then(user => {
      // login successful if there's a jwt token in the response
      if (user.access_token) {
        // store user details and jwt token in local storage to keep user logged in between page refreshes
        localStorage.setItem("user", JSON.stringify(user));
      }

      return user;
    })
    .catch(error => {
      return { error };
    });
}

//AUTH SAGA
export function* login(action) {
  const { username, password } = action.payload;
  const response = userService.login(username, password);
  console.log(response);
  if (response.error) {
    yield put({ type: actions.LOGIN_FAILURE, payload: response.error });
  } else {
    yield put(actions.loginUserSuccessful());
    yield delay(1000);
    // yield history.push("/");
  }
}

//AUTH ACTIONS
export function loginUserSuccessful() {
  return { type: LOGIN_SUCCESS };
}

//AUTH REDUCER
export function authentication(state = initialState, action) {
  const { payload } = action;

  switch (action.type) {
    case actions.LOGIN_SUCCESS:
      return {
        loggedIn: true,
        user: action.user
      };
    case actions.LOGIN_FAILURE:
      return state;
    case actions.USERS_LOGOUT:
      return state;
    case actions.LOGIN_TOGGLE_MODAL:
      const { isLoginModalOpen } = payload;
      return {
        ...state,
        isLoginModalOpen
      };
    default:
      return state;
  }
}

I have a login menu item, which when the user is logged in (as indicated by "user" and "loggedIn" being populated in store) will be switched with a "member" menu item. The login form is a part of the header component.

So when I log in the backend gets called, the token is set (USER SERVICE), this happens through a saga (AUTH SAGA). And when the user is logged in, the action "loginUserSuccessful" is called (LOGIN ACTION). This will call the reducer which updates the state with the user and "loggedIn" (AUTH REDUCER)

The problem is that "loggedIn" is being set to true, and the state is updated BEFORE the "user" object is set. So when the promise finally resolves, the user is set, but the header is not updated. So it only gets the new state when I reload the page.

I've noticed that for some reason when the action is called from the saga, I can pull "user" from the action even though I don't manually set it when I call loginUserSuccessful - I got this from a tutorial, so I am not entirely sure how it works - I am still new.

I am sure I am doing something wrong. But maybe someone can assist? Let me know more information is needed.

1 Answers

1
Daniel Olsen On Best Solutions

Found the answer. So apparently the saga action attaches the promise to the action. But that is not immediately resolved. All I needed to do was to send the user data along as the payload. Then it worked.