Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
845 views
in Technique[技术] by (71.8m points)

Call redux action in axios interceptor

I store logged in user data in localstorage. I also validate JWT token in axios interceptor and if it's expired I will refresh it. so I need to update store with new user data and JWT token and in order to do that, I need to call redux action that I have in my Auth module.

AuthRedux.js

export const actionTypes = {
  Login: "[Login] Action",
  Logout: "[Logout] Action",
  UserRequested: "[Request User] Action",
  UserLoaded: "[Load User] Auth API",
  SetUser: "[Set User] Action",
};

const initialAuthState = {
  user: undefined,
  authToken: undefined,
};

export const reducer = persistReducer(
  { storage, key: "myapp-auth", whitelist: ["user", "authToken"] },
  (state = initialAuthState, action) => {
    switch (action.type) {
      case actionTypes.Login: {
        const { authToken } = action.payload;
        return { authToken, user: undefined };
      }

      case actionTypes.Logout: {
        // TODO: Change this code. Actions in reducer aren't allowed.
        return initialAuthState;
      }

      case actionTypes.UserLoaded: {
        const { user } = action.payload;
        return { ...state, user };
      }

      case actionTypes.SetUser: {
        const { user } = action.payload;
        return { ...state, user };
      }

      default:
        return state;
    }
  }
);

export const actions = {
  login: (authToken) => ({ type: actionTypes.Login, payload: { authToken } }),
  logout: () => ({ type: actionTypes.Logout }),
  requestUser: (user) => ({ type: actionTypes.UserRequested, payload: { user } }),
  fulfillUser: (user) => ({ type: actionTypes.UserLoaded, payload: { user } }),
  setUser: (user) => ({ type: actionTypes.SetUser, payload: { user } }),
};

export function* saga() {
  yield takeLatest(actionTypes.Login, function* loginSaga() {
    yield put(actions.requestUser());
  });

  yield takeLatest(actionTypes.UserRequested, function* userRequested() {
    const { data: user } = yield getUserByToken();
    yield put(actions.fulfillUser(user));
  });
}

AxiosInterceptor.js

export default function setupAxios(axios, store, props) {
  axios.interceptors.request.use(
    config => {
      const {
        auth: { authToken }
      } = store.getState();

      if (authToken) {
        config.headers.Authorization = `Bearer ${authToken}`;
      }

      return config;
    },
    err => Promise.reject(err)
  );

  axios.interceptors.response.use(
    (response) => {
      console.log(props);
      return response;
    },
    function (error) {
      const originalRequest = error.config;

      if (error.response?.status === 401) {
        if (error.response.data === "refresh_token") {
          // refresh token and set new user data
          // question is how can I call redux setUser action in here and update state
        }
        else if (error.response.data === "invalid_token") {
          window.localStorage.clear();
          window.location.href = '/auth/login';
        }
        else { }
      }

      if (!originalRequest._retry) {
        originalRequest._retry = true;
        return axios(originalRequest);
      }

      return Promise.reject(error);
    }
  );
}

My question is how can I call reducer setUser action in interceptor and update state

question from:https://stackoverflow.com/questions/65899023/call-redux-action-in-axios-interceptor

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

You can dispatch actions from outside of a component when you have access to the store with store.dispatch(anAction), in your case you can do:

 store.dispatch(setUser())

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...