인프런 "한 입 크기로 잘라먹는 Next.js" 수강
페이지의 동작을 강제로 지정하는 옵션들
앞의 dynamicParams도 여기에 속하고, 캐싱/정적화 방식까지 페이지 성격을 딱! 정해줄 수 있다.
그 중 가장 자주 사용하는 옵션인 dynamic이라는 옵션에 대해서 살펴보자.
dynamic특정 페이지를
static또는dynamic으로 “강제” 설정.
export const dynamic = 'auto' | 'force-dynamic' | 'force-static' | 'error';
auto(기본): 아무것도 강제하지 않음. Next가 페이지 내용을 보고 자동 판정.force-dynamic: 매 요청마다 새로 렌더링(동적 페이지).force-static: 정적으로 고정(SSG처럼 캐싱).error: 정적 렌더링이 불가능하면 빌드 타임에 에러를 띄워줌.Search 페이지에 error로 두면 couldn't be rendered statically 같은 에러로 잡아줌.)✅ 검색/필터처럼 요청마다 데이터가 바뀌는 페이지는
auto(=동적 판단)나 force-dynamic이 안전!
브라우저에 저장되는 캐시
페이지 이동을 효율적으로 진행하기 위해 페이지의 일부 데이터를 보관함
RSC Payload(서버 컴포넌트 결과물) 안에는
등이 모두 들어있다.
Next.js는 여기서 레이아웃 부분만 뽑아서 클라이언트 라우터 캐시에 자동 저장해둔다.
이후 다른 페이지로 네이게이션할 때,
즉, 공통 UI(헤더/사이드바/탑바)는 재다운로드 X, 바뀌는 페이지 내용만 최소 요청으로 가져온다!
마치 캐싱된 데이터처럼 그대로 레이아웃을 사용하게 되고,
그 외에 페이지 컴포넌트나 기타 등의 서버 컴포넌트에 해당하는 데이터들은 따로 요청해서 별도로 받아오는 동작을 수행한다.
클라이언트 라우터 캐시(Client Router Cache)는 브라우저 측에 저장되는 캐시로, 한 번 방문한 페이지의 레이아웃 정보만 따로 보관해 둔다.
이후 사용자가 다른 페이지로 이동할 때, 이미 저장된 공통 레이아웃 데이터를 다시 서버에서 불러오지 않고 재사용함으로써 페이지 이동 속도를 최적화하는 기술이다.
덕분에 중복된 레이아웃을 중복으로 요청받지 않음!
import { ReactNode, Suspense } from 'react';
import Searchbar from '../../components/searchbar';
export default function Layout({ children }: { children: ReactNode }) {
return (
<div>
<div>{new Date().toLocaleDateString()}</div>
<Suspense fallback={<div>Loading...</div>}>
<Searchbar />
</Suspense>
{children}
</div>
);
}
라우팅으로 페이지를 왔다 갔다 해도 날짜가 안 바뀌는 걸 확인
→ 이 컴포넌트가 레이아웃이라 클라이언트 라우터 캐시에 보관되어 다시 렌더링되지 않기 때문.
새로고침하면 날짜가 갱신
→ 브라우저 캐시(클라이언트 라우터 캐시)는 새로고침/탭 종료 시 비움.
페이지 이동에는 강하고, 새로고침에는 초기화된다!
레이아웃에서 “시간/랜덤값” 같은 매 순간 달라지는 값을 렌더링하면,
네비게이션 시에는 안 바뀌는 게 정상 (캐시 때문).
→ 페이지 컴포넌트에서 다루거나 클라이언트 컴포넌트 + 이펙트로 처리.
검색 페이지처럼 동적 함수(쿼리스트링/쿠키/헤더)를 쓰면
억지로 force-static 하면 동작 망가짐. auto나 force-dynamic 추천!
레이아웃에 클라이언트 훅(useSearchParams)을 쓸 땐
"use client" + <Suspense> 로 비동기 흐름을 안전하게 감싸기.
라우트 세그먼트 옵션으로 "페이지 성격"을 명확히 하고, 클라이언트 라우터 캐시로 "레이아웃 재사용"하면
▶ 기깔난 App Router 네비게이션!