✅ 클라이언트에서 데이터를 가져오는 경우
클라이언트에서 데이터를 가져올 때 데이터베이스를 직접 쿼리하면 데이터베이스 비밀이 노출될 수 있으므로 데이터베이스를 직접 쿼리해서는 안 됩니다.
기본적으로 Next.js는 성능을 개선하기 위해 경로를 미리 렌더링하는데, 이를 정적 렌더링이라고 합니다. 따라서 데이터가 변경되면 대시보드에 반영되지 않습니다.
이 패턴이 반드시 나쁜 것은 아닙니다. 다음 요청을 하기 전에 조건이 충족되기를 원하기 때문에 워터폴이 필요한 경우가 있을 수 있습니다
예를 들어 사용자의 ID와 프로필 정보를 먼저 가져오고 싶을 수 있습니다. ID를 확보한 다음에는 해당 사용자의 친구 목록을 가져올 수 있습니다. 이 경우 각 요청은 이전 요청에서 반환된 데이터에 따라 조건부로 이루어집니다.
⚠️ 그러나 이러한 동작은 의도치 않게 성능에 영향을 미칠 수도 있습니다.
워터폴을 방지하는 일반적인 방법은 모든 데이터 요청을 동시에, 즉 병렬로 시작하는 것입니다.
JavaScript에서는 Promise.all() 또는 Promise.allSettled() 함수를 사용하여 모든 프로미스를 동시에 시작할 수 있습니다. 예를 들어, data.ts에서는 fetchCardData() 함수에서 Promise.all()을 사용하고 있습니다:
이 패턴을 사용하면 다음과 같이 할 수 있습니다:
모든 데이터 가져오기를 동시에 실행하여 성능을 향상시킬 수 있습니다.
모든 라이브러리나 프레임워크에 적용할 수 있는 네이티브 JavaScript 패턴을 사용합니다.
그러나 이 JavaScript 패턴에만 의존할 경우 한 가지 단점이 있습니다. 하나의 데이터 요청이 다른 모든 데이터 요청보다 느리면 어떻게 될까요?
정적 렌더링을 사용하면 빌드 시(배포할 때) 또는 재검증 중에 서버에서 데이터 가져오기 및 렌더링이 이루어집니다. 그런 다음 결과는 콘텐츠 전송 네트워크(CDN)에 배포 및 캐시될 수 있습니다.
💚 정적 블로그 게시물이나 제품 페이지와 같이 데이터가 없거나 사용자 간에 공유되는 데이터가 없는 UI에 유용
동적 렌더링을 사용하면 요청 시(사용자가 페이지를 방문할 때) 각 사용자에 대한 콘텐츠가 서버에서 렌더링됩니다.
서버 구성 요소 또는 데이터 가져 오기 함수 내에서 unstable_noStore라는 Next.js API를 사용하여 정적 렌더링을 선택 해제할 수 있다
// ...
import { unstable_noStore as noStore } from 'next/cache';
export async function fetchRevenue() {
// Add noStore() here to prevent the response from being cached.
// This is equivalent to in fetch(..., {cache: 'no-store'}).
noStore();
// ...
}
export async function fetchLatestInvoices() {
noStore();
// ...
}
export async function fetchCardData() {
noStore();
// ...
}
export async function fetchFilteredInvoices(
query: string,
currentPage: number,
) {
noStore();
// ...
}
export async function fetchInvoicesPages(query: string) {
noStore();
// ...
}
export async function fetchFilteredCustomers(query: string) {
noStore();
// ...
}
export async function fetchInvoiceById(query: string) {
noStore();
// ...
}
대시보드를 동적으로 만드는 것은 좋은 첫 번째 단계입니다.
⚠️ 하지만... 이전 장에서 언급한 한 가지 문제가 여전히 남아 있습니다. 하나의 데이터 요청이 다른 모든 데이터 요청보다 느리면 어떻게 될까요?
느린 데이터 가져오기를 시뮬레이션해 보겠습니다. data.ts 파일에서 콘솔 로그의 주석 처리를 해제하고 fetchRevenue() 내에서 setTimeout을 설정합니다
✅ 동적 렌더링을 사용하면 애플리케이션은 가장 느린 데이터 불러오기 속도만큼만 빨라진다.