0
votes

This is stemming off of this SO Question

I am trying to integrate redux-thunk with my API middleware. The current flow of logic is like this:

action dispatched from component this.props.onVerifyLogin();

=>

action goes to action creator which creates an API call to the middleware like so:

// imports

const verifyLoginAC = createAction(API, apiPayloadCreator);

export const verifyLogin = () => dispatch => {
  return verifyLoginAC({
    url: "/verify/",
    method: "POST",
    data: {
      token: `${
        localStorage.getItem("token")
          ? localStorage.getItem("token")
          : "not_valid_token"
      }`
    },
    onSuccess: result => verifiedLogin(dispatch, result),
    onFailure: result => dispatch(failedLogin(result))
  });
};

const verifiedLogin = (dispatch, data) => {
  console.log("verifiedLogin");
  const user = {
    ...data.user
  };
  dispatch(setUser(user));
  dispatch({
    type: IS_LOGGED_IN,
    payload: true
  });
};

// failedLogin function

const setUser = createAction(SET_USER);

apiPayloadCreator in utils/appUtils:

const noOp = () => ({ type: "NO_OP" });

export const apiPayloadCreator = ({
  url = "/",
  method = "GET",
  onSuccess = noOp,
  onFailure = noOp,
  label = "",
  isAuthenticated = false,
  data = null
}) => {
  return {
    url,
    method,
    onSuccess,
    onFailure,
    isAuthenticated,
    data,
    label
  };
};

and then the middleware intercepts and performs the actual API call: // imports // axios default config

const api = ({ dispatch }) => next => action => {
  next(action);
  console.log("IN API");
  console.log("Action: ", action);
  // this is where I suspect it is failing. It expects an action object
  // but is receiving a function (see below for console.log output)
  if (action.type !== API) return;

  // handle Axios, fire onSuccess/onFailure, etc

The action is created but is a function instead of an action creator (I understand this is intended for redux-thunk). But when my API goes to check action.type it is not API so it returns, never actually doing anything including call the onSuccess function. I have tried to also add redux-thunk before api in the applyMiddleware but then none of my API actions fire. Can someone assist?

Edit:

This is the received data to the API middleware:

ƒ (dispatch) {
    return verifyLoginAC({
      url: "/verify/",
      method: "POST",
      data: {
        token: "" + (localStorage.getItem("token") ? localStorage.getItem("token") : "not_valid_toke…

Status Update:

Still unable to get it work properly. It seems like redux-saga has a pretty good following also, should I try that instead?

1
This is a lot of code to process. Can you try and reduce it to the important bits? e.g. all the axios request handling is unimportant to the problem I believe. Also, which one is the action that you want to be processed by redux-thunk? verifyLogin? - flq
I tried to reduce it as far as possible the rest is essential to get a clear image. Really all I want is to setUser after verifying that the token is still valid. before redux-thunk it was firing the IS_LOGGED_IN action but not the SET_USER action. I was told in the previous SO question that I would need to do this asynchronously and that I should use redux-thunk. Per the answer in the previous Q, I wired up the verifyLogin AC to use redux-thunk. now neither IS_LOGGED_IN nor SET_USER fire properly. I also added the received data to the API to edit. - CHBresser

1 Answers

0
votes

My API was interferring. I switched to redux-saga and got everything working like so:

/**
 * Redux-saga generator that watches for an action of type
 * VERIFY_LOGIN, and then runs the verifyLogin generator
 */
export function* watchVerifyLogin() {
  yield takeEvery(VERIFY_LOGIN, verifyLogin);
}

/**
 * Redux-saga generator that is called by watchVerifyLogin and queries the
 * api to verify that the current token in localStorage is still valid.
 * IF SO: SET loggedIn = true, and user = response.data.user
 * IF NOT: SET loggedIn = false, and user = {} (blank object}
 */
export function* verifyLogin() {
  try {
    apiStart(VERIFY_LOGIN);
    const token = yield select(selectToken);
    const response = yield call(axios.post, "/verify/", {
      // use redux-saga's select method to select the token from the state
      token: token
    });
    yield put(setUser(response.data.user));
    yield put(setLoggedIn(true));
    apiEnd(VERIFY_LOGIN);
  } catch (error) {
    apiEnd(VERIFY_LOGIN);
    yield put(setLoggedIn(false));
    yield put(setUser({})); // SET USER TO BLANK OBJECT
  }
}