Next 13버전에서는 App 디렉토리 신규로 추가되었습니다. 공유 레이아웃, 중첩된 라우팅, 로딩 상태, 에러 핸들링 등을 지원하는 새로운 앱 라우터가 출시하였습니다. 관련 블로그 글
참고: 앱과 페이지 폴더 둘 다 사용이 가능합니다 대신 앱 라우터는 페이지 라우터보다 우선시됩니다. 서로 다른 디렉토리에 있는 라우트가 동일한 URL 경로로 해석되어서는 안 되며, 이렇게 되면 충돌을 방지하기 위해 빌드 시간에 에러가 발생합니다. 따라서 app 폴더를 이용할 경우 page 폴더를 삭제해주는 것이 좋습니다.
각 레이아웃을 파일로 분리시켜 사용합니다.
모든 컴포넌트가 Sever Component (static compoent)가 됩니다
=> Server Component를 사용하기 싫다면 최상단에 "use client"를 작성해야 합니다.
폴더, 파일 규칙들이 변경이 되었습니다.
app 라우팅 규칙
라우팅 파일
layout: .js .jsx .tsx 레이아웃
page: .js .jsx .tsx 페이지
loading: .js .jsx .tsx 로딩 UI
not-found: .js .jsx .tsx 찾을 수 없는 UI
error: .js .jsx .tsx 오류 UI
global-error: .js .jsx .tsx 전역 오류 UI
route: .js .ts API 엔드포인트
template: .js .jsx .tsx 재렌더링 레이아웃
default: .js .jsx .tsx 병렬 라우트 폴백 페이지
중첩 라우트
folder: 라우트 세그먼트
folder/folder: 중첩된 라우트 세그먼트
동적 라우트
[folder]: 동적 라우트 세그먼트
[...folder]: 모든 세그먼트 포착
[[...folder]]: 선택적 모든 세그먼트 포착
라우트 그룹과 프라이빗 폴더
(folder): 라우팅에 영향을 주지 않고 라우트 그룹화
_folder: 폴더와 모든 자식 세그먼트를 라우팅에서 제외
병렬 및 인터셉트 라우트
@folder: 명명된 슬롯
(.)folder: 동일한 레벨 인터셉트
(..)folder: 한 단계 위 인터셉트
(..)(..)folder: 두 단계 위 인터셉트
(...)folder: 루트에서 인터셉트
메타데이터 파일 규칙
앱 아이콘
favicon: .ico 파비콘 파일
icon: .ico .jpg .jpeg .png .svg 앱 아이콘 파일
icon: .js .ts .tsx 생성된 앱 아이콘
apple-icon: .jpg .jpeg, .png 애플 앱 아이콘 파일
apple-icon: .js .ts .tsx 생성된 애플 앱 아이콘
오픈 그래프와 트위터 이미지
opengraph-image: .jpg .jpeg .png .gif 오픈 그래프 이미지 파일
opengraph-image: .js .ts .tsx 생성된 오픈 그래프 이미지
twitter-image: .jpg .jpeg .png .gif 트위터 이미지 파일
twitter-image: .js .ts .tsx 생성된 트위터 이미지
SEO
sitemap: .xml 사이트맵 파일
sitemap: .js .ts 생성된 사이트맵
robots: .txt 로봇 파일
robots: .js .ts 생성된 로봇 파일
"use client" 지시문은 import 전에 파일의 최상단에서 정의되어야 합니다.
"use client"를 모든 파일에 정의할 필요는 없습니다. 클라이언트 모듈 경계는 한 번만, "진입점(entry point)"에서, 정의해주면 그 안으로 import된 모든 모듈이 클라이언트 컴포넌트로 간주됩니다.
서버 컴포넌트와 클라이언트 컴포넌트를 사용해야할 기준을 알고 사용을 하면 성능 최적화인 웹을 만들 수 있습니다.
이 표는 서버 컴포넌트와 클라이언트 컴포넌트의 다양한 사용 사례를 요약합니다:
// next.config.js
const nextConfig = {
+ experimental: {
+ appDir: true
+ }
}
<head/>
에 들어가는 메타 데이터입니다.@next/head
와 동일합니다.app
경로 최상위 Layout입니다. 컴포넌트 이름을 RootLayout으로 지어야합니다.
동적 세그먼트란 값이 변하는 Path 값을 의미합니다. 예를들어 detail/32 번째 게시물을 호출하였을 때 우린 32번째 게시물을 가져온다고 볼 수 있고 이는 다른 값들로 변하면서 다른 게시물을 호출해줄 수 있습니다. 이를 통해 다른 값들을 가져올 수 있습니다.
type postDetailParamsType = {
postId: number
}
const PostPage = ({params}: { params: postDetailParamsType }) => {
const [state, setState] = useState<postType>()
const router = useRouter();
useEffect(() => {
loadData(params.postId).then(res => setState(res))
}, [params.postId])
return <>
<button onClick={router.back}>뒤로가기</button>
<h3>{state?.title}</h3>
<h3>{state?.body}</h3>
<h3>{state?.userId}</h3>
</>
};
next 13에서 app directory를 이용한 경우,
client에서 렌더링 하도록 하려면 "use client" 키워드를 사용해야 합니다.
하지만, "use client"를 사용하면 useRouter은
NextRouter was not mounted.라는 에러가 발생하며 사용할 수 없습니다.
따라서 useNavigation을 사용해야 합니다. 대신, useNavigation에는 queries/dynamicPaths/paths과 같은 데이터가 존재하지 않아,
query 등의 정보가 필요한 경우에는 usePathname를 같이 사용하면 됩니다.
사용방법은 아래와 같습니다.
'use client';
import { usePathname, useRouter } from 'next/navigation';
const pathname = usePathname();
const router = useRouter();
next 13 + app directory + "use client" 키워드를 사용할 때는
'next/router'가 아닌 'next/navigation' 모듈을 이용하면 됩니다.