在 axios 拦截器中调用 redux 动作

时间:2021-01-26 09:47:08

标签: react-redux

我将登录的用户数据存储在 localstorage 中。我还在 axios 拦截器中验证 JWT 令牌,如果它已过期,我将刷新它。所以我需要用新的用户数据和 JWT 令牌更新存储,为了做到这一点,我需要调用我在我的 Auth 模块中的 redux 操作。

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);
    }
  );
}

我的问题是如何在拦截器中调用 reducer setUser 操作并更新状态

1 个答案:

答案 0 :(得分:2)

当您可以使用 store.dispatch(anAction) 访问商店时,您可以从组件外部调度操作,在您的情况下,您可以这样做:

 store.dispatch(setUser())