일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- jest
- react
- 호키스
- HTML
- javascript
- 스위프트
- 자바스크립트 자료구조
- 리액트
- TDD
- 자바스크립트
- 호키도키
- 비동기
- IOS
- hokidoki
- queue
- 계명대 이종호
- SWIFT
- 힛잇
- 자료구조
- 개발자
- 개발
- 스벨트
- 리액트 예제
- hokeys
- Hitit
- 이종호
- data structure
- Svelte
- 계명대
- 자스민
- Today
- Total
Dog foot print
app router의 기본 파일들 (page, layout, template) 본문
기존 pages
와 달리 app
은 매우 복잡한 폴더 구조와 파일구조를 가지고 있다. 이는 폴더구조를 이용하여, 다양한 기능들을 제공하려는 노력으로 보이는데, 개인적으로 “폴더구조가 너무 깊어 복잡하고 쓰임이 정해진 파일들을 얼마나 잘 활용 할 수 있을까?” 라는 생각이 든다.
Page file
이제 더 이상 파일명을 기준으로 하위 경로를 생성하지 않는다. 하위 경로는 폴더명을 기준으로 생성된다. 이렇게 생성된 page
파일들은 자신이 속한 폴더의 인덱스 경로로 지정된다. 예를 들어 /about/page.tsx
파일은 /about
과 일치하며, /about/more/page.tsx
파일은 /about/more
경로와 일치하게 된다.
Props
interface Params{
[key in string] : string | string[]
}
interface PageProps{
params? : Params,
searchParams? : Params
}
Example | URL | params |
app/shop/[slug]/page.js | /shop/1 | { slug: '1' } |
app/shop/[category]/[item]/page.js | /shop/1/2 | { category: '1', item: '2' } |
app/shop/[...slug]/page.js | /shop/1/2 | { slug: ['1', '2'] } |
No more getServerSideProps & getStaticProps
import { getTodos } from "@/api/fake";
import styles from "./page.module.css";
// app/page.tsx
export default async function Home() {
const todos = await getTodos();
return (
<main className={styles.main}>
{todos.map((v) => (
<div key={v.id}>{v.title}</div>
))}
</main>
);
}
이전과 달리 경로의 엔드포인트를 담당하는 page.tsx
에서는 더 이상 getServerSideProps
와 getStaticProps
, getStaticPaths
가 사용되지 않는다. 이는 page.tsx
에서 기본으로 내보낸 컴포넌트가 server-component
이며, 컴포넌트 내부에서 데이터를 패칭하고 캐싱하는 형태로 getServerSideProps
와 getStaticProps
를 대체하였다.
Tip : 서버 컴포넌트와 데이터 캐싱과 관련하여 자세한 내용은 아래의 링크를 참조하면 된다.
Building Your Application: Caching
https://nextjs.org/docs/app/building-your-application/rendering/server-components
Layout file
Layout
파일은 요청을 받은 페이지까지의 레이아웃을 정의한다. 해당 페이지로 향하는 경로중에 layout
컴포넌트가 존재하면, 페이지가 레이아웃에 의해 중첩되어 레이아웃을 구성한다. 이 layout파일도 page파일과 동일하게 server-component
로써 이곳에서 데이터를 패칭 할 수 있다.
No more _app.tsx && _document.tsx
이전 pages 폴더에서 app.tsx
와 _document.tsx
파일은 각각 다음과 같은 역할을 하였는데, 삭제되었고 아래의 역할은 이제 app 경로내 최상단 layout 파일에서 이루어져야 한다.
- _app.tsx : 가장 먼저 실행되는 컴포넌트로써, 모든 페이지에 공통으로
Provider
들로 감싸거나 레이아웃을 적용할 때 사용. - _document.tsx : 공통으로 적용되는
html
,head
,body
를 컨트롤 하는 역할로 사용된다.
_app.tsx와 _document와 다른 변경사항으로는 다음과 같다.
- hook과 react와 관련된 내용을 직접 호출 할 수 없다.
- 클라이언트 컴포넌트를 호출 하는 것으로 이를 대체한다.
- metaData와 관련된 값들은 중첩된 곳에서 정의한 것으로 대체 될 수 있다.
next/document
에서Head
,Body
,Html
을 호출하지 않아도 된다.pageProps
를 프롭스로 취급하지 않는다.
import "./globals.css";
import Providers from "@/Providers";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<head>
<title>헬로월드</title>
</head>
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}
html
을 구성하던 _document
파일이 삭제되었으니 이를 app폴더 최상위 layout
파일은 필수이다.
Props
Tip : params의 경우 호출되는 동일한 경로의 page와 같은 파라메터가 전달된다. 만약 중첩구조인 layout이 위치한 폴더의 path paramter
가 존재하지 않는 경우 빈 객체인 params
를 받는다.
interface LayoutProps{
children : ReactNode,
params? : Params
}
Example | URL | params |
app/shop/[slug]/page.js | /shop/1 | { slug: '1' } |
app/shop/[category]/[item]/page.js | /shop/1/2 | { category: '1', item: '2' } |
app/shop/[...slug]/page.js | /shop/1/2 | { slug: ['1', '2'] } |
Layout files do not received Props
page파일과 다르게 Layout파일은 searchParams
를 프롭스로 받지 않는다. 그 이유는 페이지 파일간 공유되는 레이아웃은 경로에 의해 사용될 레이아웃 파일이 결정되고 searchParam
의 변경시 동일한 하위 path
를 가지는데 불필요하게 재 렌더링할 이유가 없기 때문이다.
searchParam
이 필요하고 변경시 사용해야한다면 layout
파일에 useSearchParam
을 사용하는 클라이언트 컴포넌트를 사용하도록 하자.
Template File
이 파일은 하위 경로에 사용되는 page
파일을 감싸는 형태라는 점과 server-component
라는 점에서 layout
과 매우 유사하다.
//app/more/template.tsx
import { ReactNode } from "react";
export default function Template({ children }: { children: ReactNode }) {
return <div>{children}</div>;
}
//app/more/layout.tsx
export default function Layout({ children }: { children: ReactNode }) {
return <div>{children}</div>;
}
layout
파일과 매우 유사하지만 특이점이 있는데, 이 파일은 아래의 코드처럼 routeParam
이 key가 되어 작동한다는 것이다. 즉 routeParam
이 변경될때마다 새롭게 컴포넌트를 생성한다.
<Layout>
{/* Note that the template is given a unique key. */}
<Template key={routeParam}>{children}</Template>
</Layout>
Layout과 Template 컴포넌트 초기화 조건
Layout : 변경된 URL경로에서 layout파일이 위치한 경로까지 pathParam
의 변경이 존재하는 경우.
Template : 변경된 URL경로에서 pathParam
이 변경되거나 사용하는 페이지파일이 변경되는 경우.
/more/1 -> /more/2 로 URL이동시
layout file | 컴포넌트 초기화 |
/app/more/layout.js | X |
/app/more//layout.js | O |
/app/more//detail/layout.js | X |
/app/more/template.js | O |
/app/more//template.js | O |
/app/more//detail/template.js | X |
/more/1 -> /more/1/detail 로 URL이동시
layout file | 컴포넌트 초기화 |
/app/more/layout.js | X |
/app/more//layout.js | X |
/app/more//detail/layout.js | O |
/app/more/template.js | X |
/app/more//template.js | O |
/app/more//detail/template.js | O |
/more/1/detail -> /more/1/comment 로 URL이동시
layout file | 컴포넌트 초기화 |
/app/more/layout.js | X |
/app/more//layout.js | X |
/app/more//comment/layout.js | O |
/app/more/template.js | O |
/app/more//template.js | O |
/app/more//comment/template.js | O |
이처럼 레이아웃은 사용하는 pathParam
만 같다면 새롭게 컴포넌트를 생성하지 않는데 반해 template
파일은 사용하는 페이지가 변경될때마다 컴포넌트를 새롭게 생성한다. 이를 이용해, 페이지가 변경될때 마다 새롭게 상태와 사이드 이펙트를 발생시켜야하는 기능에 유리하다.
권장 사용 예시 :
- 기능이 useState나 useEffect의 사용과 연관되는 경우.
- ex : 페이지 별로 로깅을 하는 경우. (아날리틱스가 이를 대체가능함)
- ex : 페이지당 피드백을 줄 수 있는 양식
- 기존 프레임워크 기능을 변경하려는 경우
- layout은 페이지를 요청할때, 한번만 loading 상태를 보여주고 변경시에는 보여주지 않지만 template는 페이지가 변경될때 마다 loading 상태를 보여줄 수 있다.
페이지가 변경될때마다 상태가 초기화되어야 하는 공통의 UI.
Props
Tip : params의 경우 호출되는 동일한 경로의 page와 같은 파라메터가 전달된다. 만약 중첩구조인 layout이 위치한 폴더의 path paramter
가 존재하지 않는 경우 빈 객체인 params
를 받는다.
interface TemplateProps{
children : ReactNode,
}