Next์ 2022 ์ปจํผ๋ฐ์ค๋ฅผ ํตํด Next 13์ beta ๋ฒ์ ์ด ์๊ฐ๊ฐ ๋๋ฉด์ ๋ง์ ๋ถ๋ถ์ ๋ณํ๊ฐ ์์์ ์ ์ ์์๋ค. (์ฐ์ ๋๋ ํ ๋ฆฌ ๊ตฌ์กฐ๋ถํฐ..!)
beta ๋ฒ์ ์ document๋ฅผ ์ฝ์ด๋ด๋ ค๊ฐ๋ค๋ณด๋ ์๊ฐ๋ณด๋ค ๋ง์ ๋ด์ฉ์ด ๋ด๊ฒจ ์์ด์ ํ์์ playground ๋ ํฌ์์ ํ๋์ฉ ์ ์ฉํด๋ณด๋ฉด์ ๋์(?)๋ณด๋ ์ค์ ๋ชจ๋ ๊ฒ์ ๋ค ์ตํ๊ณ ๊ธ์ ๋จ๊ธฐ๋ค๊ฐ๋ ๋์ด ์์ ๊ฒ ๊ฐ์์ ์ฐ์ ์ ์ผ๋ก ํผ์ง๋งํ๊ฒ ์ด๋ค ๋ณํ๊ฐ ์๋์ง๋ฅผ Next ์ฌ์ดํธ์ blog ๊ธ์ ๋ฒ์ญ ํ๋ฉด์ ์ ์ด๋ณด๋ ค๊ณ ํ๋ค! (ํน์๋ ์ค๋ฒ์ญ์ด ์๋ค๋ฉด ์ธ์ ๋ ์๋ ค์ฃผ์ธ์ โบ๏ธ)
app
ย ๋๋ ํ ๋ฆฌ๋ ์์ง ๋ฒ ํ ๋ฒ์ ์ด๋ผ ํ๋ก๋์
์์ ์ฌ์ฉํ๋ ๊ฒ์ ์ถ์ฒํ์ง ์๋๋ค.pages
๋๋ ํ ๋ฆฌ๋ ์ฌ์ ํ ์ํฌํธ ๋ ์์ ์ด๋ค.ํฅํ app
๋๋ ํ ๋ฆฌ๊ฐ ์ํฌํธํ ๋ด์ฉ๋ค์?
async
์๋ฒ ์ปดํฌ๋ํธ๋ค๊ณผ ํ์ฅ๋ fetch
API๋ก ์ปดํฌ๋ํธ ๋ ๋ฒจ์ fetching์ด ๊ฐ๋ฅํด์ง๋ค.app
- page.js // index route (/)
- blog
- layout.js // ์ฌ๋ฌ ํ์ด์ง ์ฌ์ด์์ UI๋ฅผ ๊ณต์ ํ ์ ์๋ค.
app/
๋๋ ํ ๋ฆฌ๋ Server Components๋ค์ ์ฌ์ฉํ๋ค. 'use client';
import { useState } from 'react';
export default function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>);
}
app/
๋๋ ํ ๋ฆฌ ์์์๋ ์ ์ง์ ์ธ ๋ ๋๋ง๊ณผ ๋๋ถ์ด ๋ฐ์ดํฐ๊ฐ ํ์์ ๋์ง ์๋ ํ์ด์ง๋ค์ ๋ถ๋ถ๋ค์ ์ฆ๊ฐ์ ์ธ ๋ ๋๋ง์ด ๊ฐ๋ฅํ๋ค.// app/page.js
async function getData() {
const res = await fetch('https://api.example.com/...');
// The return value is *not* serialized
// You can return Date, Map, Set, etc.
return res.json();
}
// This is an async Server Component
export default async function Page() {
const data = await getData();
return <main>{/* ... */}</main>;
}
getServerSideProps
,ย getStaticProps
, getInitialProps
์ฒ๋ผ ํ์ฉ์ด ๊ฐ๋ฅํ๋ฉฐ SSG, SSR, ISR์ ๋ชจ๋ ์ฅ์ ๋ค์ ํ๋์ API์์ ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค.// This request should be cached until manually invalidated.
// Similar to `getStaticProps`.
// `force-cache` is the default and can be omitted.
fetch(URL, { cache: 'force-cache' });
// This request should be refetched on every request.
// Similar to `getServerSideProps`.
fetch(URL, { cache: 'no-store' });
// This request should be cached with a lifetime of 10 seconds.
// Similar to `getStaticProps` with the `revalidate` option.
fetch(URL, { next: { revalidate: 10 } });
app
๋๋ ํ ๋ฆฌ ์์์๋ Server Components๋ค ์์์ ๋ฐ์ดํฐ ๋ถ๋ฌ์ค๊ธฐ๋ฅผ ๊ถ์ฅnext dev
์์๋ง ์ง์๋๋ฉฐ next dev --turbo
๋ก ์คํํ ์ ์๋ค.import Image from 'next/image';
import avatar from './lee.png';
function Home() {
// "alt" is now required for improved accessibility
// optional: image files can be colocated inside the app/ directory
return <Image alt="leeerob" src={avatar} placeholder="blur" />;
}
size-adjust
์์ฑ์ ํ์ฉํ์ฌ ์๋์ ์ผ๋ก layout์ ๋ณํ๋ฅผ ์์ ์ค๋ค.๋ธ๋ผ์ฐ์ ์์ํด์ ๊ตฌ๊ธ๋ก ์ด๋ค ์์ฒญ๋ ๋ณด๋ด์ง์ง ์๊ฒ๋๋ค!
import { Inter } from '@next/font/google';
const inter = Inter();
<html className={inter.className}>
import Link from 'next/link'
// Next.js 12: `<a>` has to be nested otherwise it's excluded
<Link href="/about">
<a>About</a>
</Link>
// Next.js 13: `<Link>` always renders `<a>`
<Link href="/about">
About
</Link>
@vercel/og
๊ฐ ์ถ๊ฐ๋์ด Next.js๋ง์ผ๋ก๋ og ์ด๋ฏธ์ง๋ฅผ ๋ง๋ค ์ ์๊ฒ ๋์๋ค.// pages/api/og.jsx
import { ImageResponse } from '@vercel/og';
export const config = {
runtime: 'experimental-edge',
};
export default function () {
return new ImageResponse(
(
<div
style={{
display: 'flex',
fontSize: 128,
background: 'white',
width: '100%',
height: '100%',
}}>
Hello, World!
</div>),
);
}
swcMinify
์์ฑ์ด false โ true<a>
์ฌ์ฉํ์ง ์์. ๊ธฐ์กด์ ์ฌ์ฉํ๋ next/link์๋ legacyBehavior ์์ฑ์ ์ถ๊ฐํ์ฌ ๊ธฐ์กด ๊ธฐ๋ฅ๋ค์ ์ฌ์ฉํ๊ฑฐ๋ <a>
ํ๊ทธ๋ฅผ ์ญ์ ํ์ฌ ์๋ก์ด next/link๋ก ์
๊ทธ๋ ์ด๋target
์ต์
์ด ์ ๊ฑฐ