작성
·
30
·
수정됨
0
안녕하세요 강사님 좋은 강의 잘 듣고 있습니다!
useSuspenseQuery를 사용 중에 고민이 생겨서 질문 드립니다.
제가 구현하고 있는 프로젝트의 대부분 API는 인증이 필요합니다.refresh token
은 http only 쿠키로 관리하고, access token
은 쿠키에 저장하고, 요청 헤더에 넣어 인증을 하고 있습니다.
useSuspenseQuery
를 사용하는 페이지에서 SSR 단계에 401 에러가 발생합니다.
이후 CSR 전환 시에는 정상적으로 데이터를 불러와 화면은 최종적으로 렌더링됩니다.
해당 페이지를 dynamic import
로 CSR 강제하면 401이 발생하지 않습니다.
제가 추정한 원인은
클라이언트 컴포넌트 내부라도 초기 렌더링 시 SSR 패스에서 useSuspenseQuery
가 실행되어 서버에서 API 요청이 발생.
이때 공통 axios 인스턴스가 클라이언트 전용 방식으로 쿠키를 읽어 헤더에 토큰을 주입하도록 구현되어 있어, 서버 환경에서는 토큰을 읽지 못해 401이 발생하는 것으로 판단했습니다.
해결을 위해 시도한 방법
prefetchQuery
+useSuspenseQuery
조합으로, prefetchQuery
단계에서 next/headers
를 통해 서버 환경에서 토큰을 읽어 주입하면 401이 사라졌습니다.
다만, 모든 useSuspenseQuery
호출 지점마다 prefetchQuery
를 추가하는 것은 과도하다고 느껴 대안을 모색 중입니다.
질문 사항
왜 SSR에서 실행되나요?
클라이언트 컴포넌트 내부에서 호출하는데도 useSuspenseQuery
가 SSR 렌더링 단계에서 동작하는 메커니즘을 정확히 이해하고 싶습니다.
useSuspenseQuery
의 단점/주의점
강의에서는 주 사용을 권장해 주셨는데, 모든 데이터 관리에 useQuery
대신 useSuspenseQuery
사용하는게 좋은건지 실제 서비스에서 고려해야 할 단점이나 주의사항이 궁금합니다.
401을 피하는 권장 패턴
제 환경처럼 서버에서 토큰을 읽지 못해 401이 나는 경우,
제가 시도한 방법 인prefetchQuery
적용 외에 권장되는 표준 패턴이 있을까요?
prefetchQuery
를 여러 곳에서 사용할 때의 리스크
여러 페이지/쿼리에서 prefetchQuery
를 널리 적용하면 TTFB 지연, 직렬화된 캐시의 HTML 페이로드 증가, 중복 호출 등의 문제가 커질 수 있을까요?
그렇다면 적절한 적용 기준이나 완화 전략이 궁금합니다.
그리고 어떤 기준으로 prefetchQuery
를 적용하면 좋을지도 궁금합니다.
문서와 블로그, GPT 등을 찾아봤지만 명확히 정리하기 어렵고, 제가 질문을 드릴 수 있는 최고 전문가라고 생각하여 의견을 여쭙니다.
긴글 읽어주셔서 감사합니다!
아래 에러가 발생하는 예시 코드 첨부 드립니다. (APage를 CSR로 강제하면 에러 미발생)
import Spinner from "@/components/common/spinner/Spinner";
import A from "@/components/pages/A";
import { Suspense } from "react";
import { ErrorBoundary } from "react-error-boundary";
interface APageProps {
params: {
id: string;
};
}
export default async function APage({
params,
}: APageProps) {
const { id } = params;
const parsedId = parseInt(id);
return (
<ErrorBoundary fallback={<div>에러가 발생했습니다</div>}>
<Suspense fallback={<Spinner fullscreen />}>
<A id={parsedId} />
</Suspense>
</ErrorBoundary>
);
}
"use client";
import { useGetAList } from "@/api/A/queries/useGetAList";
interface AProps {
id: number;
}
export default function A ({ id }: AProps) {
const { data: probiomeList } = useGetAList(id);
// 생략
import { queryKeys } from "@/constants/queryKeys";
import { UseSuspenseQueryCustomOptions } from "@/types";
import { useSuspenseQuery } from "@tanstack/react-query";
import { getAList } from "../A";
import { AList } from "@/types/A";
export function useGetAList(
id: number,
queryOptions?: UseSuspenseQueryCustomOptions<AList>
) {
return useSuspenseQuery({
queryFn: () => getAList(id),
queryKey: [
queryKeys.A.BASE,
queryKeys.A.GET_A_LIST,
id,
],
...queryOptions,
});
}
답변 1
1
이번 강의에 수업노트를 보시면 Suspense랑 useSuspenseQuery는 둘 다 SSR됩니다. SSR이 필요한 경우 쓰시면 됩니다.
SSR시에는 반드시 토큰이 서버에서 접근 가능해야 하고 그러면 보통 쿠키를 많이 사용합니다.
prefetchQuery는 fetch가 넥스트와 호환되는 경우에는
데이터캐시로 요청 횟수를 최적화할 수 있습니다.