/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
, getStaticProps
page.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-store
next: { 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
를 기본으로 전달받는다error
reset
: 현 에러상태를 초기화 하는 함수🌟 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 = false
generateStatincParams
내부에서 다시 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'