Search code examples
reactjsreact-reduxredux-toolkit

Uncaught (in promise) Error: Invalid hook call. Hooks can only be called inside of the body of a function component


SO i have an axios interceptors to return an error and set the error status into reducer using dispacth from redux-toolkit:

import axios from "axios";
import TokenService from "./token.service";
import { useDispatch } from "react-redux";
import { setSTATUS } from "../actions/status";
import { Navigate } from "react-router-dom";
const secretKey = {
  apps_id: process.env.REACT_APP_APPS_ID,
  secret_key: process.env.REACT_APP_API_KEY,
};
// eslint-disable-next-line react-hooks/rules-of-hooks

const instance = axios.create({
  baseURL: process.env.REACT_APP_BASE_URL,
  headers: {
    "Content-Type": "application/json",
    token: TokenService.getLocalAccessToken(),
  },
});

instance.interceptors.request.use(
  (config) => {
    const token = TokenService.getLocalAccessToken();
    console.log("token interceptors", token);
    if (token) {
      console.log("Tken WOrking");
      // config.headers["Authorization"] = "Bearer " + token;
      // config.headers["x-access-token"] = token; // for Node.js Express back-end
      config.headers["token"] = token; // for Node.js Express back-end
    }
    return config;
  },
  (error) => {
    return Promise.reject(error);
  }
);

instance.interceptors.response.use(
  (res) => {
    console.log("res", res);
    return res;
  },
  async (err) => {
    const dispatch = useDispatch();
    dispatch(setSTATUS(err.response.status));
    const originalConfig = err.config;
    console.log("originalConfig", err);

    if (
      originalConfig.url !== "/api/auth/login" &&
      err.message === "Request failed with status code 401"
    ) {
      console.log("error", err);
      console.log("originalConfig", originalConfig);
      // Access Token was expired
      if (
        err.response.data.status === 401 &&
        err.response.data.message === "Error token : jwt expired"
      ) {
        originalConfig._retry = true;

        try {
          console.log("refresh token");
          const rs = await instance.post(
            "/token/generate_token",
            // refreshToken: TokenService.getLocalRefreshToken(),
            secretKey
          );
          console.log("rs", rs);
          const token = rs.data.data;
          TokenService.updateLocalAccessToken(token);
          TokenService.removeUser();
          instance(originalConfig);
          return <Navigate to="/login" />;
        } catch (_error) {
          return Promise.reject(_error);
        }
      }
    }

    return Promise.reject(err);
  }
);

export default instance;

But when it getting error response of 500, instead of dispacth it into reducer i got this error... Uncaught (in promise) Error: Invalid hook call. Hooks can only be called inside of the body of a function component.

Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.
    at Object.throwInvalidHookError (react-dom.development.js:14906:1)
    at useContext (react.development.js:1504:1)
    at useReduxContext (useReduxContext.js:21:1)
    at useStore (useStore.js:17:1)
    at useDispatch (useDispatch.js:14:1)
    at api.js:43:1

can someone tellme where did i do wrong here?


Solution

  • useDispatch is react hook, so it has to respect hook laws, you can only call a hook from component or custom hook. Instead you could access redux store directly and get dispatch from there

    import store from './store'; // correct path to your store
    
    const {dispatch} = store;