Gila - caching layer 추가(Next.js app router에서 react-query 적용하기)

박상준·2024년 9월 17일

Gila

목록 보기
24/25

캐시 추가하기

이걸 하게된 가장 큰 이유는 우리가 사용하는 방식은 next.js에서 캐싱지원이 안된다. 만약 우리가 fetch를 사용해서 서버를 통해 db에 접근해 데이터를 받아오는 방식이였다면 next에서 자동으로 fetch의 기능을 확장해 캐싱을 해준다. 즉, 같은 요청을 여러번 보내도 처음만 로딩이 있을뿐 이후에는 없다는 것이다. 하지만 우리는 prisma를 기반으로 db에 저장된 모델을 불러오고 있기 때문에 캐싱이 안된다.

심지어 우리는 서버 액션도 아니고 클라이언트에서 브라우저 접속 위치를 기반으로 요청을 보내고 있다보니 서버 캐시를 사용하기에도 까다로운 것이다.

그래서 해당 기능을 유저가 확인하기 위해서는 매번 2초씩 로딩 시간을 거쳐야한다. 당연히 유저 입장에선 매번 로딩이 되는 것이 당연히 불편하고 불필요하다고 느낄것이다. 그래서 해당 기능을 클라이언트 캐시를 사용해서 처리해보려고 한다.

react-query

클라이언트에서 캐싱을 하는 가장 보편적인 라이브러리다. 그리고 우리는 로케이션값을 계산해서 저장하고 그 위치를 기반으로 주변 활동을 불러오는데 위치를 계산하는 시간이 걸리기에 react-query의 enabled 옵션을 통해 바로 캐싱하지 않고 기다리는 기능이 필요했다. 추가적으로 내가 사용해본적이 있어서 클라이언트 캐싱으로 사용하기에 적합하다고 생각했다.

적용하기

Provider 설정

react-query를 사용할 수 있도록 layout에 Provider를 설정해주겠다.

function Providers({ children }: { children: React.ReactNode }) {
  const [queryClient] = useState(
    () =>
      new QueryClient({
        defaultOptions: {
          queries: {
            staleTime: 3600 * 1000,
          },
        },
      }),
  );

  return (
    <QueryClientProvider client={queryClient}>
      {children}
      <ReactQueryDevtools initialIsOpen={false} />
    </QueryClientProvider>
  );
}

provider에 react-query에 사용할 기본 옵션을 설정해주고 QueryClientProvider에 전달해주면 된다. 내가 설정한 옵션은 react-query 지속 시간이다. 나는 지역이 1시간 이내에 변경되기는 어렵다고 판단해 1시간으로 지정해줬다. 그리고 추가적으로 개발모드에서 query값을 확인하기 위해 devtool을 같이 넣어줬다.

useState를 사용하는 이유: 여기에서 useState의 기본 값으로 지정하는 이유는 초기에 값을 설정하고 setter함수를 설정하지 않음으로써 초기 참조성을 지켜주는 것이다. 쉽게 말해서 더이상 변경될 일이 없도록 방지해주는 것이라고 생각하면 될듯하다.

        <Providers>
          <NextSSRPlugin routerConfig={extractRouterConfig(ourFileRouter)} />
          <Toaster />
          <div className="w-full tall:my-0 tall:mx-auto tall:flex justify-center">
            <GilaLayout />
            <div className="max-w-[420px] mx-auto tall:mx-0 tall:bg-white_light tall:w-[420px] pt-16 tall:pt-0">
              {children}
            </div>
          </div>
        </Providers>

이제 프로젝트 전체 layout에 만들어준 Provider를 넣어주면 된다. 이제 프로젝트 전체에서 react-query를 사용할 수 있다.

react-query 적용하기

  const [userLocation, setUserLocation] = useState<string[]>([]);
  const { data } = useQuery({
    queryKey: ['activityByLocation', userLocation],
    queryFn: () =>
      getActivitiesByLocation({
        location: userLocation[0],
        secondeLocation: userLocation[1],
        size: 5,
      }),
    enabled: userLocation.length > 0,
  });

간단하게 useQuery를 사용해서 저장해준다. 그리고 enabled 옵션을 통해 로케이션 값이 세팅되기 전에는 쿼리 저장을 하지 않도록 해줬다. 그리고 이제 react-query를 통해 받은 데이터를 기존 코드에 적용시켜준다.

{userLocation[0] && data ? (
  <ActivitySlide recommendList={data.activities} />
) : (
  <div className="px-5">
    <ActivityCardSkeleton />
  </div>
)}


react-query devtool로 확인해보면 처음 로케이션값이 없을때에는 데이터 요청을 하지 않는다. 하지만 이후에 로케이션 값이 설정되면 데이터를 요청한다. 당연히 이제 다른 페이지로 이동하더라도 클라이언트 캐싱을 통해 추가적인 데이터 요청없이 지역 데이터를 받아올 수 있다.

옆의 네트워크를 보면 지역 위치 조회 후에 activity-list로 요청이 간것이 볼수 있다.

다른 페이지로 이동했다가 돌아오는 경우에는 지역 위치만 조회하고 다시 activity-list요청을 확인할 수 없다. 클라이언트 캐시를 통해 처리했기 때문이다.

여기에서 조금더 개선하는 것은 위치 조회도 캐싱처리해서 처음만 요청하도록 하는 것이다. 아직 그부분은 건들어보지 않아서 다음에 최적화해보겠다.

마무리

next.js에서 react-query를 사용할 이유가 딱히 없다고 생각했는데 이런 문제들이 발생할 줄은 생각도 못했다. 당연한걸 고려하지 못한걸보니 아직 많이 부족하다는 것을 느낀다. 그래도 전에는 매번 페이지 접근시마다 2초정도 발생하던 로딩을 없앴다는 점에서 나름 뿌듯하다.

prisma를 무료 db와 연동해서 사용하다보니 아무래도 속도측면에서 불리한 점이 많다. 지금도 대시보드의 각 페이지마다 currentUser를 받는 로직이 포함되어 있다. 이 부분도 데이터 로딩을 발생시킨다고 생각한다. 그래서 유저 정보도 매번 db에서 조회하는 것이 아니라 auth.js session에 저장해서 더 빠르게 데이터를 받아오도록 설계할 것이다. 다음은 auth.js session에 데이터 추가하고 코드 리팩토링을 하겠다.

profile
개인 블로그 플렛폼도 운영중입니다(https://blog-park.vercel.app/)

0개의 댓글