/app 경로는 아직 experimental 로 구분되기 때문에 next.config.js 파일에 아래와 같은 설정을 추가next.config.js :
/** @type {import('next').NextConfig} */
const nextConfig = {
+ experimental: {
+ appDir: true
+ }
...
}
module.exports = nextConfig
experimental 이기 때문에 경고 메세지를 같이 출력 🫠 tsconfig.json 에 필요한 설정 알아서 추가해줌warn - You have enabled experimental feature (appDir) in next.config.js.
warn - Experimental features are not covered by semver, and may cause unexpected or broken application behavior. Use at your own risk.
info - Thank you for testing `appDir` please leave your feedback at https://nextjs.link/app-feedback
We detected TypeScript in your project and reconfigured your tsconfig.json file for you. Strict-mode is set to false by default.
The following suggested values were added to your tsconfig.json. These values can be changed to fit your project's needs:
- include was updated to add '.next/types/**/*.ts'
- plugins was updated to add { name: 'next' }
/pages 경로를 삭제하지 않으면 /pages기준으로 실행 /pages 경로 삭제후 실행하면 /app 경로를 알아서 상성해주면서 추가적으로 필요한 코드파일 미리 생성 app
|__ head.{js,tsx}
|__ layout.{js,tsx}
|__ page.{js,tsx}
<head> 에 들어가는 메타 데이터 @next/head 의 역할export default function Head() {
return (
<>
<title></title>
<meta content="width=device-width, initial-scale=1" name="viewport" />
<link rel="icon" href="/favicon.ico" />
</>
)
}
/app 경로의 최상단 layout_app.tsx, _document.tsx 의 역할/app 의 모든 하위 경로가 공통적으로 사용하는 코드를 실행/app 의 모든 하위 경로가 공통적으로 사용하는 UI 구현/app/page/layout.tsx 와 같이 nested 구조로 특정 페이지에서만 개별 layout 사용 가능export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html>
<head />
<body>{children}</body>
</html>
)
}
/pages/index.{js,tsx} 와 동일/app ?getServerSideProps, getStaticPropspage.tsx:
caching하기 때문에 Static 페이지처럼 구현// SSG (getStaticProps equivalent)
const getData = async () => {
const res = await fetch('https://....')
const data = await res.json()
return data?.items as Array<{id: string, name: string}>
}
export default async function Page() {
const data = await getData()
return (
<div>
{data?.map((d) => <div key={d.id}>{d.name}</div>)}
</div>
)
}
revalidate가 필요하다면 next: { revalidate: number } 추가const getData = async () => {
// ISR
const res = await fetch('https://....',
+ {
+ next: { revalidate: 10 }
+ }
)
const data = await res.json()
return data?.items as Array<{id: string, name: string}>
}
cache: 'no-store' 설정 추가cache 추가 옵션force-cache : defaultno-storenext: { revalidate : number }// SSR (getServerSideProps equivalent)
const getData = async () => {
const res = await fetch('https://....',
+ { cache: 'no-store' }
)
const data = await res.json()
return data?.items as Array<{id: string, name: string}>
}
...
app
|__ ...
|__ posts
| |__ loadng.{js.tsx}
| |__ error.{js.tsx}
| |__ [slug].{js,tsx}
loading.{js,tsx} :
suspense 의 활용 (behind the scene)error.{js,tsx} :
error.{js,tsx}는 아래와 같은 props를 기본으로 전달받는다errorreset : 현 에러상태를 초기화 하는 함수🌟 Client Component ?
/app 경로에선 모든 컴포넌트는 기본적으로 React의 server component 를 사용useEffect, useState 와 같은 client-side hook을 사용하기 위해서는 최상단에 'use client'를 추가해야 한다+ 'use client';
import { useEffect } from 'react';
export default function Error({
error,
reset,
}: {
error: Error;
reset: () => void;
}) {
useEffect(() => {
console.error(error);
}, [error]);
return (
<div>
<p>Something went wrong!</p>
<button onClick={() => reset()}>Reset error boundary</button>
</div>
);
}
[slug].{js.tsx} :
const getPost = async (id: string) => {
const res = await fetch(`https://..../${id}`,
{
next: { revalidate: 10 }
}
)
const data = await res.json()
return data
}
export default async function Page({ params }: any) {
const data = await getPost(params.id)
return (
<div>
{data.id}
{data.name}
</div>
)
}
getStaticPaths equivalent+ export async function generateStaticParams() {
+ const posts = await getPosts()
+ return posts.map((post) => ({
+ slug: post.slug
+ }))
+ }
...
Fetch APIfetch를 사용하지 않고 SDK나 다른 API를 사용할 때 캐싱 설정을 하는 방식은 아래와 같이 Next.js 13 에서 재공하는 다양한 변수를 export할 수 있다export const dynamic = 'auto',
dynamicParams = true,
revalidate = 0,
fetchCache = 'auto',
rumtime = 'nodejs',
preferredRegin = 'auto'
export const dynamic = 'auto'
// 'auto' | 'force-dynamic' | 'error' | 'force-static'
auto : default - cache as much as possibleforce-dynmaic : all cache disabled on fetch() requestsgetServerSideProps*(){ cache: 'no-store', next: { revalidate: 0 } }error :getStaticProps() in the pages directory.{ cache: 'force-cache' }dynamicParams = falsegenerateStatincParams 내부에서 다시 dynamicParams = true로 설정 변경 가능force-static:cookie() , header(), useSearchParams() 가 항상 empty value를 리턴하게 하며 static으로 페이지 생성export const dynamicParams = true // true | false,
true : generateStaticParams 에 포함되지 않은 페이지일 경우 접근시 페이지 생성false : generateStaticParams 에 포함되지 않은 페이지일 경우 접근시 404 export const fetchCache = 'auto'
// 'auto' | 'default-cache' | 'only-cache'
// 'force-cache' | 'force-no-store' | 'default-no-store' | 'only-no-store'
default :fetch() request를 캐싱한다fetch() request는 캐싱하지 않는다export const runtime = 'nodejs'
// 'experimental-edge' | 'nodejs'
export const preferredRegion = 'auto'
// 'auto' | 'home' | 'edge' | 'string'