08. 정적 렌더링, 동적 렌더링


이전 장에서는 대시보드 개요 페이지에 대한 데이터를 가져왔다. 그러나 현재 설정의 두 가지 제한 사항에 대해 간단히 논의했다.

  • 데이터 요청이 의도하지 않은 워터폴 전송이 되었다.
  • 대시보드는 정적이므로 데이터 업데이트가 애플리케이션에 반영되지 않는다.

 

이번 장에서는 아래의 주제를 다룬다.

  • 정적 렌더링이 무엇이며 애플리케이션 성능을 어떻게 향상시킬 수 있는지 알아보자.
  • 동적 렌더링이란 무엇이며 언제 사용해야 할까?
  • 대시보드를 동적으로 만드는 다양한 접근 방식을 알아보자.
  • 느린 데이터 가져오기를 시뮬레이션하여 무슨 일이 일어나는지 확인해보자.

 

정적 렌더링이란 무엇입니까?

정적 렌더링을 사용하면 빌드 시(배포 시) 또는 유효성 재검사 중에 데이터 가져오기 및 렌더링이 서버에서 발생한다. 

그 다음 결과는 CDN(Content Delivery Network)에 배포되고 캐시될 수 있다.

 

사용자가 애플리케이션을 방문할 때마다 캐시된 결과가 제공된다. 정적 렌더링에는 몇 가지 이점이 있다.

 

  • 더 빠른 웹사이트 - 사전 렌더링된 콘텐츠를 캐시하고 전 세계적으로 배포할 수 있다. 이를 통해 전 세계 사용자가 웹사이트 콘텐츠에 더욱 빠르고 안정적으로 액세스할 수 있다.
  • 서버 로드 감소 - 콘텐츠가 캐시되기 때문에 서버는 각 사용자 요청에 대해 콘텐츠를 동적으로 생성할 필요가 없다.
  • SEO - 사전 렌더링된 콘텐츠는 페이지가 로드될 때 이미 콘텐츠를 사용할 수 있으므로 검색 엔진 크롤러가 색인을 생성하기가 더 쉽다. 이를 통해 검색 엔진 순위가 향상될 수 있다.

 

정적 렌더링은 정적 블로그 게시물이나 제품 페이지와 같이 사용자 간에 공유되는 데이터나 데이터가 없는 UI에 유용하다. 정기적으로 업데이트되는 개인화된 데이터가 있는 대시보드에는 적합하지 않을 수 있다.

 

정적 렌더링의 반대는 동적 렌더링이다.

 

동적 렌더링이란?

동적 렌더링을 사용하면 요청 시(사용자가 페이지를 방문할 때) 각 사용자의 콘텐츠가 서버에서 렌더링된다. 동적 렌더링에는 몇 가지 이점이 있다.

  • 실시간 데이터 - 동적 렌더링을 통해 애플리케이션은 실시간 또는 자주 업데이트되는 데이터를 표시할 수 있다. 이는 데이터가 자주 변경되는 애플리케이션에 이상적이다.
  • 사용자별 콘텐츠 - 대시보드나 사용자 프로필과 같은 개인화된 콘텐츠를 제공하고 사용자 상호 작용을 기반으로 데이터를 업데이트하는 것이 더 쉽다.
  • 요청 시간 정보 - 동적 렌더링을 사용하면 쿠키나 URL 검색 매개변수와 같이 요청 시간에만 알 수 있는 정보에 액세스할 수 있다.

 

/app/lib/data.ts

// ...
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();
  // ...
}
참고: 불안정한_noStore는 실험적인 API이며 향후 변경될 수 있다. 자신의 프로젝트에서 안정적인 API를 사용하려는 경우 세그먼트 구성 옵션 에서  "export const dynamic = "force-dynamic"을 사용할 수도 있다.

 

느린 데이터 페치 시뮬레이션

대시보드를 동적으로 만드는 것이 첫 번째 단계이다. 그러나... 이전 장에서 언급한 한 가지 문제가 여전히 남아 있다. 하나의 데이터 요청이 다른 모든 데이터 요청보다 느리면 어떻게 될까?

느린 데이터 가져오기를 시뮬레이션해 보겠다. data.ts 파일에서 fetchRevenue() 내부에 있는 console.log 및 setTimeout의 주석 처리를 제거하자.

 

/app/lib/data.ts

export async function fetchRevenue() {
  try {
    // We artificially delay a response for demo purposes.
    // Don't do this in production :)
    console.log('Fetching revenue data...');
    await new Promise((resolve) => setTimeout(resolve, 3000));
 
    const data = await sql<Revenue>`SELECT * FROM revenue`;
 
    console.log('Data fetch completed after 3 seconds.');
 
    return data.rows;
  } catch (error) {
    console.error('Database Error:', error);
    throw new Error('Failed to fetch revenue data.');
  }
}

이제 새 탭에서 http://localhost:3000/dashboard/를 열고 페이지를 로드하는 데 시간이 더 오래 걸리는 것을 확인해보자. 터미널에는 다음 메시지도 표시된다.

Fetching revenue data...
Data fetch completed after 3 seconds.

 

여기서는 느린 데이터 가져오기를 시뮬레이션하기 위해 인위적인 3초 지연을 추가했다. 그 결과 이제 데이터를 가져오는 동안 전체 페이지가 차단된다.

개발자가 해결해야 하는 공통 과제는 다음과 같다.

동적 렌더링을 사용하면 애플리케이션 속도는 가장 느린 데이터를 가져오는 속도만큼만 빨라진다.

  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유