简体   繁体   中英

How to stop React from finishing render when axios.interceptors.response handles the error?

I am working on a react app and I use tokens and refresh tokens for authentication. Whenever the backend returns a 401 , the axios.interceptors.response picks it up and tries to refresh my token. If it succeeds, it will reinitiate the original call with the updated headers. See the code below:

// To avoid infinite loops on 401 responses
let refresh = false;

axios.interceptors.response.use(
  (resp) => resp,
  async (error) => {
    if (error.response.status === 401 && !refresh) {
      refresh = true;

      const response = await axios.post(
        "/api/auth/refresh",
        {},
        { withCredentials: true }
      );

      if (response.status === 200) {
        axios.defaults.headers.common[
          "Authorization"
        ] = `Bearer ${response.data["accessToken"]}`;

        return axios(error.config);
      }
    }
    refresh = false;
    return error.response;
  }
);

This by itself works great, but not in combination with the code below in one of my components:

const [pages, setPages] = useState();
const [error, setError] = useState();

const navigate = useNavigate();

useEffect(() => {
    async function fetchInfo() {
      const response = await getMyPages();
      if (response.status === 200) {
        setPages(response.data);
      }
      else if (response.status === 401) {
        setError(t("error.notAuthorized"));
        navigate(`/login`, { replace: true });
      }
      // Any other error
      else {
        setError(t("error.unexpected"));
      }
    }
    fetchInfo();
  }, [t, navigate]);


// getMyPages function
export async function getMyPages() {
  try {
    const result = await axios.get(`/api/user/mypages`);
    return result;
  } catch (err) {
    return err.response;
  }
}

The problem is that the user is navigated to /login before the new request (with refreshed token) is made and finished. So when the new request finishes, I am not in the original component anymore and I can no longer update the pages state.

Any suggestions on how to handle this?

useEffect(() => {
    let isMounted = true;
    const controller = new AbortController();
    const getMyPages = async () => {
        try {
            const response = await axios.get(`/api/user/mypages`, {
                signal: controller.signal
            });
            isMounted && setPages(response.data);
        } catch (err) {
            navigate(`/login`, { replace: true });
        }
    }       
    getMyPages();
    return () => {
        isMounted = false;
        controller.abort();
    }
}, [])

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM