문제
client-side에서 데이터를 패칭 할 때 쿼리 스트링 등 동적으로 데이터 패칭이 필요 할 때 빌드 시 해당 API는 server-side 데이터를 가져 올 수 없으므로 빌드 에러가 나게 된다.
문제 코드
// index.tsx
const fetchOrders = useCallback(async () => {
try {
if (
!user ||
searchConditions.merchantId === undefined ||
searchConditions.sellerId === undefined
)
return;
const { totalCount, orders: fetchedOrders } = await getOrders({
merchantId: searchConditions.merchantId,
sellerId: searchConditions.sellerId,
status:
searchConditions.status !== '전체'
? [getStatusEng(searchConditions.status!) as OrderItemStatus]
: null,
startDate: searchConditions.startDate,
endDate: searchConditions.endDate,
page: pageInfo.page,
perPage: pageInfo.perPage,
});
setOrders(fetchedOrders);
setTotalCount(Number(totalCount));
} catch (error) {
handleErrorWithModal(
error,
'주문 내역을 불러오는 중 오류가 발생했습니다.',
openModal,
fetchOrders,
);
}
}, [
openModal,
setOrders,
searchConditions.merchantId,
searchConditions.sellerId,
searchConditions.status,
searchConditions.startDate,
searchConditions.endDate,
pageInfo.page,
pageInfo.perPage,
user,
]);
useEffect(() => {
if (!user) return;
fetchOrders();
}, [user, fetchOrders]);
const exportDataToExcel = async () => {
try {
if (isDownloading) return;
setIsDownloading(true);
if (
!user ||
searchConditions.merchantId === undefined ||
searchConditions.sellerId === undefined
) {
showToastMessage('잠시 후 다시 시도해주세요.', 'error', true);
return;
}
const { headers, data } = await getOrdersExcelData({
merchantId: searchConditions.merchantId,
sellerId: searchConditions.sellerId,
status:
searchConditions.status !== '전체'
? [getStatusEng(searchConditions.status!) as OrderItemStatus]
: null,
startDate: dayjs(searchConditions.startDate).format('YYYYMMDD'),
endDate: dayjs(searchConditions.endDate).format('YYYYMMDD'),
});
const fileName = `${dayjs(searchConditions.startDate).format('YYYYMMDD')}_${dayjs(searchConditions.endDate).format('YYYYMMDD')}_주문내역`;
const sheetName = '주문내역';
exportToExcel({ headers, data, fileName, sheetName });
} catch (error) {
handleErrorWithToast(
error,
'주문 내역을 엑셀로 다운로드하는 중 오류가 발생했습니다.',
showToastMessage,
);
} finally {
// NOTE: 2초 후에 다운로드 가능한 상태로 변경
setTimeout(() => setIsDownloading(false), 2000);
}
};
// route.ts
export async function GET(req: NextRequest) {
try {
const { searchParams } = new URL(req.url);
req.url을 가져오는 데 문제가 생김
설명
렌더링 방식
- 정적 생성 (Static Generation, SSG)
- 정적 HTML 생성: 빌드 타임에 HTML 파일을 생성하고, 이 파일을 정적 서버에 배포
- 빠른 응답 시간: 서버는 미리 생성된 HTML 파일 즉시 제공
- SEO 친화적: 완전히 렌더링된 HTML을 제공하므로 검색 엔진 크롤러가 쉽게 인덱싱
- 제한점: 빌드 타임에 모든 데이터를 필요로 하며, 이후에 데이터 변경 사항은 반영되지 않음
- 동적 렌더링 (Dynamic Rendering, SSR)
- 서버 사이드 렌더링: 각 요청 시마다 서버가 최신 데이터를 기반으로 HTML을 생성하여 반환
- 실시간 데이터: 항상 최신 데이터를 사용하여 페이지를 렌더링
- SEO 친화적: 서버가 완전히 렌더링된 HTML을 제공하므로 SEO에 유리
- 서버 부하: 각 요청 시마다 서버가 렌더링 작업을 수행하므로 서버 부하가 증가 할 수 있음
- 클라이언트 사이드 데이터 패칭:
- React 컴포넌트가 브라우저에서 실행
- API는 동적으로 처리: 서버는 클라이언트로부터의 요청에 따라 실시간으로 데이터를 처리하고 응답 반환
빌드 타임과 런타임 차이
- 빌드 타임: 정적 사이트 생성 시점
- 이때 Next.j는 서버 사이드 함수나 API 라우트를 실행 할 수 없음
- 모든 데이터는 정적으로 존재해야 함
- 런타임: 사용자가 페이지를 요청하는 시점. 동적 렌더링의 경우, 이 시점에서 서버가 요청을 받아 데이터를 가져와 페이지를 렌더링
- 이때 Next.js는 서버 사이드 함수나 API 라우트를 실행할 수 있음
- 최신 데이터를 가져와 페이지를 동적 생성
API 요청
- 정적 요청
getStaticProps
를 이용해 요청 시 API 요청은 정적 요청이 된다.
- 동적 요청
- server-side 및 client-side에서 요청 시 API 요청은 동적 요청이 된다.
해결 방법
// route.ts
export const dynamic = 'force-dynamic';
- 빌드 타임에 해당 API 라우트를 정적으로 생성하지 않고, 런타임에 처리하도록 하는 설정
- 빌드 시점에 접근할 수 없는 리소스나 환경 변수를 필요로 할 때 사용
- API가 데이터베이스 쿼리, 외부 API 호출 등 빌드 타임에 실행될 수 없는 작업을 포함하는 경우 유용
- 모든 동적 요청 API에 처리할 필요는 없고, 동적 데이터가 필요한 API에만 처리
'TIL' 카테고리의 다른 글
too many clients에서 벗어나보자 (0) | 2024.08.19 |
---|---|
노션 API를 공지사항에 적용해보면 어떨까? (0) | 2024.08.19 |
token을 관리해보자! (0) | 2024.08.19 |
x-api-key authorization (0) | 2024.08.19 |
supertest시 :id가 500으로 떨어진다면? (0) | 2024.08.19 |