[Next.js] - Next 13 Experimental AppDir

NoowaH·2022년 11월 29일
6

Next.js

목록 보기
12/17

AppDir

  • Next.js 13 프레임워크의 새로운 디렉토리 구조

How to Use

  • /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" />
		</>
	)
}

Layout

  • RootLayout:
    - /app 경로의 최상단 layout
    - _app.tsx, _document.tsx 의 역할
    - /app 의 모든 하위 경로가 공통적으로 사용하는 코드를 실행
    - /app 의 모든 하위 경로가 공통적으로 사용하는 UI 구현
    - Header
    - Footer
  • NestedLayout
    - /app/page/layout.tsx 와 같이 nested 구조로 특정 페이지에서만 개별 layout 사용 가능
export default function RootLayout({
	children,
}: {
	children: React.ReactNode
}) {
	return (
		<html>
		<head />
		<body>{children}</body>
		</html>
	)
}

Page

  • 각 페이지의 루트 파일
  • /pages/index.{js,tsx} 와 동일

Why /app ?

1. Simpler SSR, SSG codes

  • 😮 no more getServerSideProps, getStaticProps
  • more like original javascript code

page.tsx:

SSG (Static Side Generation)

  • fetch 함수의 추가 설정이 없다면 Next에서 알아서 페이지를 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>
	)
}

ISR (Incremental Static Generation)

  • Static 페이지의 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}>
}

SSR (Server Side Generation)

  • SSR 형태의 페이지로 만들고 싶다면 아래와 같이 cache: 'no-store' 설정 추가
  • cache 추가 옵션
    - force-cache : default
    - no-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}>
}
...

Dynamic Routes

	app
	|__ ...
	|__ posts
	|   |__ loadng.{js.tsx}
	|   |__ error.{js.tsx}
	|   |__ [slug].{js,tsx}

loading.{js,tsx} :

  • React suspense 의 활용 (behind the scene)
  • data fetching fallback loading UI

error.{js,tsx} :

  • data fetching failure UI
  • ❗️ must be a `client component
  • 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>
	)
}

Generate Static Params

  • getStaticPaths equivalent
+ export async function generateStaticParams() {
+ 	const posts = await getPosts()
+ 	return posts.map((post) => ({
+		slug: post.slug
+ 	}))
+ }
...

Cache setting without using Fetch API

  • 비동기 데이터를 fetch를 사용하지 않고 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 possible
    - force-dynmaic : all cache disabled on fetch() requests
    - getServerSideProps*()
    - { cache: 'no-store', next: { revalidate: 0 } }
    - error :
    - getStaticProps() in the pages directory.
    - { cache: 'force-cache' }
    - auto configure dynamicParams = false
    - generateStatincParams 내부에서 다시 dynamicParams = true로 설정 변경 가능
    - force-static:
    - cookie() , header(), useSearchParams() 가 항상 empty value를 리턴하게 하며 static으로 페이지 생성

export const dynamicParams = true // true | false,
  • 생성되지 않은 dynamic 페이지 접근 시 행동 설정
    - 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'
  • advanced option
    - 기본 설정을 특수한 이유로 오버라이딩 할 때만 사용하는 것을 권장
  • default :
    - Next.js 는 dynamic functions을 실행하기 전 접근할 수 있는 모든 fetch() request를 캐싱한다
    - dynamic functions을 실행한 후 접근하는 fetch() request는 캐싱하지 않는다
  • advanced option:

export const runtime = 'nodejs'
// 'experimental-edge' | 'nodejs'

export const preferredRegion = 'auto'
// 'auto' | 'home' | 'edge' | 'string'
profile
조하운

0개의 댓글