1. Layout.js
- 공유 UI를 여러 페이지에서 재사용
- 페이지 전환시 리렌더링되지 않음
- 한번 마운트된 후 계속 유지되는 특성
- 상태가 유지됨
- 헤더, 네비게이션 바와 같은 지속적으로 유지되어야 하는 UI 요소에 사용
- 리렌더링되지 않아 성능상 이점
2. Templete.js
- 매 페이지 전환시 새로운 인스턴스 생성
- 상태가 유지되지 않음 (not preserved)
- 매번 새로 마운트됨
- 페이지 뷰 추적 , 페이지 전환 애니메이션, 입력 값 초기화가 필요한 경우에 사용
- 컴포넌트 격리가 필요할 때도 사용
- 템플릿은 매번 새로 마운트되어 메모리 관리 필요
// Layout.tsx
'use client'
export default function Layout({ children }) {
console.log('Layout 마운트됨!') // 최초 한 번만 실행
useEffect(() => {
console.log('Layout useEffect 실행')
return () => {
console.log('Layout 언마운트됨') // 앱을 완전히 나갈 때만 실행
}
}, [])
return <div>{children}</div>
}
// Template.tsx
'use client'
export default function Template({ children }) {
console.log('Template 마운트됨!') // 페이지 전환마다 실행됨
useEffect(() => {
console.log('Template useEffect 실행')
return () => {
console.log('Template 언마운트됨') // 페이지 전환시마다 실행됨
}
}, [])
return <div>{children}</div>
}
만약 로딩 스피너를 적용하거나 방문자수를 카운트 하는 기능이 있다고 할 경우,
템플릿에서는 새로 마운트 될 때마다, 스피너가 표시되거나 방문자 수가 늘어나겠지만
레이아웃은 맨 처음 마운트 되는 1회에만 적용된다게, 두 양식의 차이라고 생각하시면 됩니다.
Suspense Boundaries 도 마찬가지 입니다.
// layout.tsx
export default function Layout({ children }) {
return (
<Suspense fallback={<LoadingSpinner />}>
{children}
</Suspense>
)
}
- 최초 로드시에만 폴백(LoadingSpinner)이 표시됨
- 페이지 전환시에는 이전 페이지 내용이 유지되다가 새 컨텐츠로 교체
// templete.tsx
export default function Template({ children }) {
return (
<Suspense fallback={<LoadingSpinner />}>
{children}
</Suspense>
)
}
- 페이지 전환할 때마다 폴백(LoadingSpinner)이 표시됨
- 매번 새로운 인스턴스가 생성되므로 로딩 상태가 항상 보임
3. 랜더링 순서
랜더링 순서로는 아래의 구조를 보시면 됩니다.
<Layout>
{/* Note that the template is given a unique key. */}
<Template key={routeParam}>{children}</Template>
</Layout>
1. Layout이 가장 바깥쪽에서 감싸고
2. Template이 그 안에서 children을 감싸는 구조
3. Template은 고유한 key를 받아 페이지 전환시마다 새로운 인스턴스 생성하게 됩니다
app/
├── layout.js // 루트 레이아웃
├── template.js // 루트 템플릿
├── page.js // 홈 페이지
└── dashboard/
├── layout.js // 중첩된 레이아웃
├── template.js // 중첩된 템플릿
└── page.js // dashboard 페이지
이런 구조라고 하면
1. Root Layout
2. Root Template
3. Page Layout (있는 경우)
4. Page Template (있는 경우)
5. Page
순으로 랜더링 되게 됩니다.
https://nextjs.org/blog/layouts-rfc
Layouts RFC
Nested routes and layouts, client and server routing, React 18 features, and designed for Server Components.
nextjs.org
4. 사용 예시
1. 분석(Analytics) + 공통 UI
Layout: 네비게이션, 헤더, 푸터 등 공통 UI
Template: 페이지별 방문 추적, 사용자 행동 분석
2. 애니메이션 + 지속적 UI
Layout: 항상 표시되는 UI 요소
Template: 페이지 전환 애니메이션
3. 상태 초기화 + 공통 기능
Layout: 전역 상태, 인증 상태 등 유지
Template: 페이지별 폼 데이터, 필터 초기화
4. 성능 최적화 + 사용자 경험
Layout: 한 번 로드된 컴포넌트 재사용
Template: 페이지별 최적화 (스크롤 위치 등)
물론 templete은 Next.js의 권장 패턴으로 반드시 사용해야하는 것은 아니며,
page 에서 직접 구현하거나, 레퍼 컴포넌트, 라이터 이벤트를 활용하며 구현도 가능합니다.
하지만 팀 협업시 의도의 명확성, 코드 구조의 일관성을 생각하면 가능하면
프로젝트의 요구사항과 팀의 선호도에 반하는 게 아니라면 사용하는 게 좋다고 생각합니다
'NEXT.js' 카테고리의 다른 글
[Next.js] redirect 함수, notFound 함수는 try/catch 밖에서 사용해야 합니다 (0) | 2025.01.04 |
---|---|
[Next.js] Next.js의 환경 변수 파일 우선순위와 용도 (0) | 2025.01.04 |
[Next.js] Server Actions 시 놓치면 안되는 revalidatePath, revalidateTag ( 데이터 캐시 관리) (0) | 2024.11.29 |
[Next.js] react 와 next의 form submit 차이( Server Actions 시 ) (0) | 2024.11.28 |
[Next.js] react 와는 다른 이미지 import 방법 설명과 Image 컴포넌트 활용하기 (0) | 2024.11.27 |