web

Axios Interceptor에서 hook 사용하기

Jaaaay 2023. 1. 24. 15:56

요구사항: API 요청에서 header에 hash key를 담아 보내야 하는 상황에서 URL에 있는 키 정보를 next/router를 통해 추출해 사용하고자 했음. 기존 Axios client 파일에서는 hook을 사용할 수 없어 해결방안을 모색.

구글링을 통해 본 대부분의 경우는 header에 key를 담는 경우에 대해서 local storage 값을 사용하고 있었다.

이를 해결하기 위해서 <APP/> 자체를 감싸줄 수 있는 훅을 생성했다.

// axiosInterceptor.tsx

import axios, { AxiosResponse } from 'axios';
import React, { useState, useEffect } from 'react';

import { useRouter } from 'next/router';
import { apiAddress, env } from '../config';

const api = axios.create({ baseURL: apiAddress[env], withCredentials: true });

const AxiosInterceptor = ({ children }: { children: React.ReactElement }) => {
  const [isSet, setIsSet] = useState(false);
  const router = useRouter();
  useEffect(() => {
    let { id } = router.query;

    if (Array.isArray(id) && id.length !== 0) {
      id = id.join('/') as string;
      console.log(id);
    }

    api.interceptors.request.use(
      (config) => {
        config.headers = {
          ANONYMOUS_KEY: id as string,
        };
        return config;
      },
      (error) => {
        console.log(error);
        return error;
      }
    );

    const interceptor = api.interceptors.response.use(
      (response: AxiosResponse) => {
        console.log(response);
        return response;
      },
      (error: unknown) => {
        return Promise.reject(error);
        // return toErrorWithMessage(error);
      }
    );
    if (id) {
      setIsSet(true);
    }

    return () => {
      api.interceptors.response.eject(interceptor);
      api.interceptors.request.eject(interceptor);
    };
  }, [router]);
  if (isSet) {
    return children;
  } else {
    return null;
  }
};

export default api;
export { AxiosInterceptor };
// _app.tsx

import type { AppProps } from 'next/app';
import { QueryClient, QueryClientProvider } from 'react-query';
import { RecoilRoot } from 'recoil';
import { AxiosInterceptor } from '../hooks/axiosInterceptor';

const queryClient = new QueryClient();

export default function App({ Component, pageProps }: AppProps) {
  return (
    <AxiosInterceptor>
      <RecoilRoot>
        <QueryClientProvider client={queryClient}>
          <Component {...pageProps} />
        </QueryClientProvider>
      </RecoilRoot>
    </AxiosInterceptor>
  );
}

useRouter()를 정상적으로 이용할 수 있었다.

Note : you must remove interceptors in useEffect return statement, because every execution of useEffect, adds a new interceptor to Axios instance.

axios 인스턴스가 useEffect마다 생성되기 때문에 리턴 문에서 제거해 줄 필요가 있다.

단점

hook 동작 전에 렌더링이 된다던지 하는 문제를 줄이기 위해 set state를 통해 hook 동작 전 렌더링을 방지해주었다. (원글의 댓글 참고)



~

예전에 필요에 의해 적용하고 지금까지 잘 사용하고 있다. 우려와는 달리 문제도 없었고 리액트 컴포넌트를 사용하듯이 이런저런 값을 편한대로 쓸 수 있어 아주 만족하며 사용하는 중...

 

 

 

참고: https://dev.to/arianhamdi/react-hooks-in-axios-interceptors-3e1h