23.07.30
오늘 한 일
- 카공실록 ky 세팅
카공실록 ky 세팅
ky
에는 hooks로 요청 전처리, 응답 후처리 등 다양한 기능을 추가할 수 있다.
요청 전에 헤더에 토큰을 추가하고, 응답 후에 만약 토큰이 만료되었다면 다시 발급하거나 로그인 페이지로 이동하는 등의 기능을 추가하기 위해 훅을 사용했다.
// instance.ts
import { retryRequest } from './retryRequest';
import { setHeader } from './setHeader';
import ky from 'ky';
const api = ky.create({
prefixUrl: process.env.NEXT_PUBLIC_API_URL,
headers: {
'Content-Type': 'application/json',
},
hooks: {
beforeRequest: [setHeader], // 토큰을 헤더에 추가
afterResponse: [retryRequest], // 토큰이 만료되었다면 재발급 or 로그인 페이지로 이동
},
});
export default api;
서버 컴포넌트에서 prefetch하기
서버 컴포넌트에서는 useQuery 같은 훅들을 사용할 수 없다. 그래서 서버 컴포넌트에서 prefetch로 데이터를 요청한 후 queryClient를 dehydrate해서 클라이언트로 보내줘야 한다.
이 과정을 간단하게 하기 위해 HydrationProvider
컴포넌트로 감사서 사용하기로 했다.
// HydrationProvider.tsx
import {
dehydrate,
Hydrate,
QueryClient,
type QueryKey,
type QueryFunction,
} from '@tanstack/react-query';
import { cache, PropsWithChildren } from 'react';
type HydrationProviderProps = {
queryKey: QueryKey;
queryFn: QueryFunction;
};
export const HydrationProvider = async ({
children,
queryKey,
queryFn,
}: PropsWithChildren<HydrationProviderProps>) => {
const getQueryClient = cache(() => new QueryClient());
const queryClient = getQueryClient();
await queryClient.prefetchQuery(queryKey, queryFn);
const dehydratedState = dehydrate(queryClient);
return <Hydrate state={dehydratedState}>{children}</Hydrate>;
};
사용법
// 서버 컴포넌트
import Child from '../components/Child';
import { Keys, getPlace } from '@/apis/place';
import { HydrationProvider } from '@/providers/HydrationProvider';
export default async function TestPage({ params: { id } }: { params: { id: string } }) {
const placeId = Number(id);
return (
<div>
<HydrationProvider queryKey={Keys.place(placeId)} queryFn={() => getPlace(placeId)}>
<Child />
</HydrationProvider>
</div>
);
}
// 클라이언트 컴포넌트
'use client';
import { useGetPlace } from '@/apis/place';
export default function Child() {
const { data } = useGetPlace(1);
return (
<div>
<h1>Child</h1>
</div>
);
}
주의할 점
HydrationProvider
컴포넌트는 비동기 서버 컴포넌트이다. 그래서 사용하게 되면 이런 에러가 뜰 수 있다.
'HydrationProvider' cannot be used as a JSX component.
Its return type 'Promise<Element>' is not a valid JSX element.
Type 'Promise<Element>' is missing the following properties from type 'ReactElement<any, any>': type, props, keyts(2786)
공식문서에 따르면, 타입스크립트 버전 5.1.3 이상, @types/react 버전 18.2.8 이상을 사용해야고 나와있다.
만약 버전을 업그레이드 할 수 없는 상황이라면, 이 컴포넌트 위에 /* @ts-expect-error Async Server Component */}
주석을 추가하면 된다.
/* @ts-expect-error Async Server Component */
<HydrationProvider>
우리 프로젝트에서는 yarn berry를 사용하고 있어서 타입스크립트 버전을 업그레이드 한 후 yarn dlx @yarnpkg/sdks vscode
로 워크스페이스의 타입스크립트 버전을 업데이트 해서 해결했다.
내일 할 일
- TS 스터디 진행
- gloddy 개발