[Next.js] Next.js 13 ์•Œ์•„๋ณด๊ธฐ

โฐ 2023-09-23 (ํ† ) 20:41:27

screener

Table of Contents

  • 1. Next.js 13







Next.js 13

React ํ”„๋กœ์ ํŠธ๋ฅผ ํ•˜๋ฉด, ์‹ญ์ค‘ํŒ”๊ตฌ๋Š” Next.js๋ฅผ ์“ฐ๊ฒŒ ๋œ๋‹ค. ์ตœ๊ทผ์— ๋ธ”๋กœ๊ทธ๋ฅผ ๊ฐœํŽธํ•˜๋ฉด์„œ create-next-app์„ ๋Œ๋ ธ๋Š”๋ฐ, 13๋ฒ„์ „์œผ๋กœ ์—…๋ฐ์ดํŠธ ๋˜๋ฉด์„œ ๋ˆˆ์— ๋„๋Š” ๋ณ€๊ฒฝ์ ์ด ์žˆ๋Š” ๋“ฏ ํ•˜๋‹ค.

๊ทธ ์ค‘ ๋ช‡๋ช‡ ๋ณ€๊ฒฝ์ ์€ ๊ธฐ์กด ์‚ฌ์šฉ๋ฒ•๊ณผ ์ƒ์ดํ•ด์ ธ์„œ ์“ฐ๋Š”๋ฐ ์‚ด์ง ์• ๋ฅผ ์ข€ ๋จน์—ˆ๋Š”๋ฐ, ์ด๋Ÿฌํ•œ ๋ณ€๊ฒฝ์ ์— ๋Œ€ํ•ด ๋‹ค๋ค„๋ณด๊ณ ์ž ํ•œ๋‹ค.

๋ณ€๊ฒฝ์ ?

13๋ฒ„์ „์ด ๋˜๋ฉด์„œ ์ •์˜๋œ ๋ณ€๊ฒฝ์ ์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

  • app Directory: ๋” ์‰ฝ๊ณ , ๋” ๋น ๋ฅด๊ณ , ๋” ์ ์€ ํด๋ผ์ด์–ธํŠธ JavaScript
    • Layouts
    • React Server Components
    • Streaming
  • Turbopack: ์ตœ๋Œ€ 700๋ฐฐ ์ด์ƒ ๋น ๋ฅธ Rust ๊ธฐ๋ฐ˜ Webpack ์ ์šฉ
  • New next/image: ๋„ค์ดํ‹ฐ๋ธŒ ๋ธŒ๋ผ์šฐ์ €์˜ lazy loading ๊ธฐ๋ฒ•์œผ๋กœ ๋”์šฑ ๋นจ๋ผ์ง„ ์ด๋ฏธ์ง€ ์ปดํฌ๋„ŒํŠธ
  • New @next/font: Zero Layout Shift๋ฅผ ์œ„ํ•œ ์…€ํ”„ ํ˜ธ์ŠคํŒ… ํฐํŠธ
  • Improved next/link: ์ž๋™ a ํƒœ๊ทธ๋กœ ๋‹จ์ˆœํ™”๋œ ๋งํฌ API

์ด ์ค‘ ๋ช‡ ๊ฐ€์ง€๋Š” ๋‚ด๋ถ€์ ์ธ ์„ฑ๋Šฅ ํ–ฅ์ƒ์ด๋ผ ์ฝ”๋“œ ์‚ฌ์šฉ์ƒ์˜ ๋ณ€๊ฒฝ์ ์€ ์—†๋‹ค.

1. App Directory ์ ์šฉ

12๋ฒ„์ „๋ถ€ํ„ฐ experimental ๊ธฐ๋Šฅ์œผ๋กœ ์ œ๊ณต๋๋˜ app Directory ๊ธฐ๋Šฅ์ด ๋ฉ”์ธ์œผ๋กœ ์˜ฌ๋ผ์˜จ ๊ฒƒ ๊ฐ™๋‹ค. ๊ทธ ๋‹น์‹œ ์‚ฌ์šฉํ•ด๋ณผ๊นŒ ํ•˜๋‹ค๊ฐ€ ์‹คํ—˜์  ๊ธฐ๋Šฅ์ด๋ผ๊ธธ๋ž˜ ๋„˜๊ฒผ๋˜ ๊ธฐ์–ต์ด ์žˆ๋‹ค.

13๋ฒ„์ „์—์„œ ๊ฐ€์žฅ ํฌ๊ฒŒ ์ฒด๊ฐ๋˜๋Š” ๋ณ€๊ฒฝ์ ์ด๋‹ค. ์ด ํ•ญ๋ชฉ์€ ์ฃผ์š” ๊ธฐ๋Šฅ ์ค‘ ํ•˜๋‚˜์ธ ๋ผ์šฐํŒ…์— ๋Œ€ํ•œ ๋ณ€๊ฒฝ์ ์ด๋‹ค.

์•„๋ž˜์˜ ์˜ˆ์‹œ๋Š” TypeScript๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํ•œ๋‹ค.


๊ธฐ์กด

๊ธฐ์กด ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

BASH

1
2
3
4
5
6
7
๐Ÿ“ฆsrc
 โ”ฃ ๐Ÿ“‚page
 โ”ƒ โ”ฃ ๐Ÿ“‚mypage
 โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“œinfo.tsx # /mypage/info
 โ”ƒ โ”ƒ โ”— ๐Ÿ“œupdate.tsx # /mypage/update
 โ”ƒ โ”ฃ ๐Ÿ“œindex.tsx # /
 โ”ƒ โ”— ๐Ÿ“œlogin.tsx # /login

์œ„์™€ ๊ฐ™์ด page๋ผ๋Š” ํด๋”์— ํŽ˜์ด์ง€ ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๋Š” ํ˜•ํƒœ๋‹ค. ํŒŒ์ผ์˜ ์ด๋ฆ„์ด ๊ณง URL์ด ๋œ๋‹ค. page/ ํ•˜์œ„์—” ๋ฐ˜๋“œ์‹œ ํŽ˜์ด์ง€ ์ปดํฌ๋„ŒํŠธ๋งŒ ์žˆ์–ด์•ผํ•˜๋ฏ€๋กœ, ์„œ๋ธŒ ์ปดํฌ๋„ŒํŠธ๋‚˜ ๋””์ž์ธ๊ฐ™์€ ํŒŒ์ผ์ด ์œ„์น˜ํ•ด์„  ์•ˆ ๋œ๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค.


๋ณ€๊ฒฝ

Next.js 13์˜ app Directory๋ฅผ ์ ์šฉํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ๊ตฌ์กฐ๊ฐ€ ๊ธฐ๋ณธ์ด ๋œ๋‹ค.

BASH

1
2
3
4
5
6
7
8
9
10
๐Ÿ“ฆsrc
 โ”ฃ ๐Ÿ“‚app
 โ”ƒ โ”ฃ ๐Ÿ“‚login
 โ”ƒ โ”ƒ โ”— ๐Ÿ“œpage.tsx # /login
 โ”ƒ โ”ฃ ๐Ÿ“‚mypage
 โ”ƒ โ”ƒ โ”ฃ ๐Ÿ“‚info
 โ”ƒ โ”ƒ โ”ƒ โ”— ๐Ÿ“œpage.tsx # /mypage/info
 โ”ƒ โ”ƒ โ”— ๐Ÿ“‚update
 โ”ƒ โ”ƒ    โ”— ๐Ÿ“œpage.tsx # /mypage/update
 โ”ƒ โ”— ๐Ÿ“œpage.tsx # /

ํŒŒ์ผ๋ช…์ด URL์ด์˜€๋˜ ๊ธฐ์กด๊ณผ ๋‹ฌ๋ฆฌ ํด๋”๋ช…์ด URL์ด ๋˜๋ฉฐ, ํด๋”๋ช… ํ•˜์œ„์—๋Š” ๋ฐ˜๋“œ์‹œ page ํŒŒ์ผ์ด ์žˆ์–ด์•ผํ•œ๋‹ค.

๋ณ€๊ฒฝ๋œ ๋ผ์šฐํŒ…์—์„ , ํŒŒ์ผ๋ช…๋งˆ๋‹ค ๋™์ž‘ํ•˜๋Š” ์—ญํ• ์ด ์ •ํ•ด์ ธ ์žˆ๋Š”๋ฐ, ๊ฐ๊ฐ์˜ ์—ญํ• ์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

ํŒŒ์ผ๋ช…์ •์˜
layoutํ˜„์žฌ ๋ฐ ํ•˜์œ„ ํŽ˜์ด์ง€์˜ ๊ณต์œ  UI ์ปดํฌ๋„ŒํŠธ
pageํŽ˜์ด์ง€ ์ปดํฌ๋„ŒํŠธ
loadingํ˜„์žฌ ๋ฐ ํ•˜์œ„ ํŽ˜์ด์ง€์˜ ๋กœ๋”ฉ UI ์ปดํฌ๋„ŒํŠธ
not-foundํ˜„์žฌ ๋ฐ ํ•˜์œ„ ๊ฒฝ๋กœ์˜ 404 ์˜ค๋ฅ˜ UI ์ปดํฌ๋„ŒํŠธ
errorํ˜„์žฌ ๋ฐ ํ•˜์œ„ ๊ฒฝ๋กœ์˜ ์˜ค๋ฅ˜ UI ์ปดํฌ๋„ŒํŠธ
global-error์ „์—ญ ์˜ค๋ฅ˜ UI ์ปดํฌ๋„ŒํŠธ
route์„œ๋ฒ„์‚ฌ์ด๋“œ API ์—”๋“œํฌ์ธํŠธ
templateํŽ˜์ด์ง€ ํ…œํ”Œ๋ฆฟ UI ์ปดํฌ๋„Œ
default๋ณ‘๋ ฌ ๋ผ์šฐํŠธ์˜ ๋Œ€์ฒด UI ์ปดํฌ๋„ŒํŠธ

๊ฐ ํด๋” ํ•˜์œ„์— ์œ„์™€ ๊ฐ™์ด ์ •์˜๋œ ํŒŒ์ผ๋ช…์„ ์ถ”๊ฐ€ํ•˜๋ฉด, ๋ณ„๋„์˜ ์—ฐ๊ฒฐ์ž‘์—… ์—†์ด ํŒŒ์ผ์„ ์„ ์–ธํ•˜๋Š”๊ฒƒ ๋งŒ์œผ๋กœ๋„ ์œ„์™€ ๊ฐ™์€ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

Next.js 13์˜ ํŽ˜์ด์ง€ ๋ Œ๋”๋ง ๊ตฌ์กฐ

Next.js์˜ ๊ณต์‹๋ฌธ์„œ์—์„œ ๊ฐ ์ปดํฌ๋„ŒํŠธ์˜ ๋™์ž‘์„ ์œ„์™€ ๊ฐ™์ด ๋ฌ˜์‚ฌํ•œ๋‹ค. Layout ์ปดํฌ๋„ŒํŠธ์™€ Template ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๊ฐ์‹ธ์ง€๊ณ , ์„ ์–ธ๋œ ๋กœ๋”ฉ, ์—๋Ÿฌ ์ปดํฌ๋„ŒํŠธ๋“ค์ด ๋ฌถ์ธ ๋’ค์— ๋น„๋กœ์†Œ ์‹ค์ œ ํŽ˜์ด์ง€ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง๋œ๋‹ค.

ํŠนํžˆ ์ด ์ค‘์—์„œ app ๋ฐ”๋กœ ํ•˜์œ„์— ์œ„์น˜ํ•˜๋Š” layout ์ปดํฌ๋„ŒํŠธ๋Š” ๋ชจ๋“  ํŽ˜์ด์ง€์— ๊ณตํ†ต์œผ๋กœ ์ ์šฉ๋˜๋Š” ์ „์—ญ ๋ ˆ์ด์•„์›ƒ์ด๋‹ค. ์ด์ „ ๋ฒ„์ „์˜ _app, _document์˜ ์—ญํ• ์„ ๋Œ€์ฒดํ•œ๋‹ค.

layout, loading ๋“ฑ, ์œ„ ํ‘œ์—์„œ ํ˜„์žฌ ๋ฐ ํ•˜์œ„๋ผ๊ณ  ๋ช…์‹œ๋œ ์ปดํฌ๋„ŒํŠธ๋“ค์€ ์ „๋ถ€ ํ•˜์œ„ ๊ฒฝ๋กœ์—๋„ ์ ์šฉ๋˜๋Š” ์ปดํฌ๋„ŒํŠธ๋“ค์ด๋‹ค.

Next.js 13์˜ ํ•˜์œ„ ํŽ˜์ด์ง€ ๋ Œ๋”๋ง ๊ตฌ์กฐ

ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ๋Š” ์œ„์™€ ๊ฐ™์ด ๋ Œ๋”๋ง๋œ๋‹ค. ๋ถ€๋ชจ์˜ ๊ณต์œ  ์ปดํฌ๋„ŒํŠธ๋“ค์ด ๊ฐ™์ด ๋ Œ๋”๋ง๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ฎ์–ด์”Œ์šฐ๋Š” ๊ฒŒ ์•„๋‹ˆ๋‹ˆ ์ฃผ์˜ํ•˜์ž.

์ด๋ฅผ ์ฝ”๋“œ๋กœ ๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.


  • app/layout.tsx

TSX

1
2
3
4
5
6
7
8
9
10
// app/layout.tsx
export default function Layout({children}: PropsWithChildren) {
  return (
    <div style={{backgroundColor: '#8F85ED', padding: 20}}>
      <p>app/layout</p>

      {children}
    </div>
  )
}

  • app/template.tsx

TSX

1
2
3
4
5
6
7
8
9
10
// app/template.tsx
export default function Template({children}: PropsWithChildren) {
  return (
    <div style={{backgroundColor: '#8B9DF7', padding: 20}}>
      <p>app/template</p>

      {children}
    </div>
  )
}

  • app/page.tsx

TSX

1
2
3
4
5
6
7
8
// app/page.tsx
export default function Page() {
  return (
    <div style={{backgroundColor: '#8AAFE1', padding: 20}}>
      <p>app/page.tsx</p>
    </div>
  )
}

๊ฒฐ๊ณผ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ๋ Œ๋”๋ง๋œ๋‹ค. (CSS๋Š” ์ž„์˜ ์ ์šฉ)

๋ Œ๋”๋ง ๊ฒฐ๊ณผ

์œ„์˜ ๊ทธ๋ฆผ๊ณผ ๊ฐ™์ด, <Layout /> ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๊ฐ€์žฅ ๋ฐ”๊นฅ์— ์œ„์น˜ํ•˜๊ณ , ๊ทธ ์ž์‹์œผ๋กœ ๋™์ผ ๊ฒฝ๋กœ์˜ <Template /> ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์œ„์น˜ํ•œ๋‹ค. ์ดํ›„ ์‹ค์ œ <Page /> ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง๋˜์–ด ํ•˜๋‚˜์˜ ํŽ˜์ด์ง€๊ฐ€ ์™„์„ฑ๋œ๋‹ค.


๋งŒ์•ฝ, app/ ํ•˜์œ„์— main์ด๋ผ๋Š” ํด๋”๋ฅผ ๋‘์–ด ํ•˜์œ„ ๊ฒฝ๋กœ๋ฅผ ์ƒ์„ฑํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ํ‘œํ˜„๋ ๊นŒ?

main/ ํด๋”์— ์•„๋ž˜์™€ ๊ฐ™์€ ํŒŒ์ผ์ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜์ž.


  • app/home/layout.tsx

TSX

1
2
3
4
5
6
7
8
9
10
// app/home/layout.tsx
export default function Layout({children}: PropsWithChildren) {
  return (
    <div style={{backgroundColor: '#ED8774', padding: 20}}>
      <p>app/home/layout</p>

      {children}
    </div>
  )
}

  • app/home/template.tsx

TSX

1
2
3
4
5
6
7
8
9
10
// app/home/template.tsx
export default function Template({children}: PropsWithChildren) {
  return (
    <div style={{backgroundColor: '#F7A079', padding: 20}}>
      <p>app/home/template</p>

      {children}
    </div>
  )
}

  • app/home/page.tsx

TSX

1
2
3
4
5
6
7
8
// app/home/page.tsx
export default function Page() {
  return (
    <div style={{backgroundColor: '#E1A97A', padding: 20}}>
      <p>app/home/page.tsx</p>
    </div>
  )
}

๋ Œ๋”๋ง ๊ฒฐ๊ณผ

๋ถ€๋ชจ์˜ ๊ณต์œ  ์ปดํฌ๋„ŒํŠธ <Layout />, <Template />๊ฐ€ ์ƒ์œ„์— ๋ Œ๋”๋ง๋˜๊ณ , ๊ทธ ํ•˜์œ„์— main/ ํด๋”์˜ ์š”์†Œ๋“ค์ด ๋ Œ๋”๋ง๋˜๋Š” ๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด ๊ตฌ์กฐ๋ฅผ ์ž˜ ํ™œ์šฉํ•˜๋ฉด ์„œ๋น„์Šค ์ „์—ญ์— ์ ์šฉํ•ด์•ผํ•  ๋ ˆ์ด์•„์›ƒ์„ ์‰ฝ๊ฒŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๊ฐ ํŽ˜์ด์ง€ ์ฃผ์ œ๋ณ„๋กœ URL์„ ๊ทธ๋ฃนํ™”ํ•ด์„œ ๋ ˆ์ด์•„์›ƒ์„ ์งœ๊ธฐ์—๋„ ์šฉ์ดํ•˜๋‹ค. ๋˜ํ•œ, ์ด๋Ÿฐ์‹์œผ๋กœ ๊ณต์œ  ์ปดํฌ๋„ŒํŠธ๋ฅผ ์•Œ๋งž๊ฒŒ ํ™œ์šฉํ•˜๋ฉด, ๋ถˆํ•„์š”ํ•œ ์ปดํฌ๋„ŒํŠธ์˜ ๋ Œ๋”๋ง์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.

๋‹ค๋งŒ ์ด๋Ÿฐ ๊ตฌ์กฐ ์ƒ ์ฃผ์˜ํ•  ์ ์ด ํ•˜๋‚˜ ์žˆ๋‹ค๋ฉด, ์ƒ์œ„์— ์„ ์–ธ๋œ ๊ณต์œ  ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ•˜์œ„์—์„œ ์ž„์˜๋กœ ์ œ์™ธํ•  ์ˆ˜ ์—†๋Š” ๊ฒƒ ๊ฐ™๋‹ค. ์ฆ‰, ํŠน์ • ํ•˜์œ„ ๊ฒฝ๋กœ์—์„  ๋ถ€๋ชจ์˜ layout.tsx ํ˜น์€ template.tsx๋ฅผ ์ œ์™ธ์‹œํ‚ฌ ์ˆ˜ ์—†์œผ๋‹ˆ, ๊ณต์œ  ์ปดํฌ๋„ŒํŠธ๋ฅผ ์„ค๊ณ„ํ•  ๋•Œ, ์ด๋Ÿฌํ•œ ์ผ€์ด์Šค๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๊ฑฐ๋‚˜, ๋ฐœ์ƒํ•ด๋„ ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š๋„๋ก ์ž˜ ์„ค๊ณ„ํ•ด์•ผํ•  ๊ฒƒ ๊ฐ™๋‹ค.

์ด ๋ฐ–์˜ ๋” ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๐Ÿ”— Next.js 13 ๋ผ์šฐํŒ… ๊ณต์‹๋ฌธ์„œ์—์„œ ํ™•์ธํ•˜์ž.

2. Server/Client ์ปดํฌ๋„ŒํŠธ์˜ ๋ช…์‹œ์  ๊ตฌ๋ถ„

Next.js์˜ ์ปดํฌ๋„ŒํŠธ๋Š” ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋กœ ๊ตฌ๋ถ„๋œ๋‹ค. ๊ฐ ์ปดํฌ๋„ŒํŠธ์˜ ๊ตฌ๋ถ„์— ๋”ฐ๋ผ ์ˆ˜ํ–‰ ๊ฐ€๋Šฅํ•œ ์—ญํ• ์ด ์กฐ๊ธˆ์”ฉ ๋‹ค๋ฅด๋‹ค.

๊ธฐ๋Šฅserverclient
๋ฐ์ดํ„ฐ Fetchโœ…โŒ
๋ฐฑ์—”๋“œ ๋ฆฌ์†Œ์Šค์— ์ง์ ‘ ์ ‘๊ทผโœ…โŒ
์„œ๋ฒ„์— ๋ฏผ๊ฐํ•œ ์ •๋ณด ๊ด€๋ฆฌ (ํ† ํฐ ๋“ฑ)โœ…โŒ
์„œ๋ฒ„์˜ ํฐ ์ข…์†์„ฑ ์œ ์ง€ / ํด๋ผ์ด์–ธํŠธ ์ธก JS ์ฝ”๋“œ ์ถ•์†Œโœ…โŒ
์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ ์‚ฌ์šฉ (onChange ๋“ฑ)โŒโœ…
์ƒํƒœ๊ด€๋ฆฌ ๋ฐ ์ˆ˜๋ช…์ฃผ๊ธฐ ์‚ฌ์šฉ (useEffect ๋“ฑ)โŒโœ…
๋ธŒ๋ผ์šฐ์ €์šฉ API ์‚ฌ์šฉ (Navigator API ๋“ฑ)โŒโœ…
์ปค์Šคํ…€ Hook ์‚ฌ์šฉโŒโœ…
React class ์ปดํฌ๋„ŒํŠธ ์‚ฌ์šฉโŒโœ…

๊ฒฐ๊ตญ ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ์˜ ๋ Œ๋”๋ง ๋ฐฉ์‹์ด SSR์ด๋ƒ, CSR์ด๋ƒ ๋ช…์‹œํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์ด์ „ ๋ฒ„์ „์˜ ๊ฒฝ์šฐ, ๋ณ„๋„์˜ ์„ ์–ธ ์—†์ด, getServerSideProps, getStaticProps ๊ฐ™์€ ๋ฉ”์„œ๋“œ์˜ ์‚ฌ์šฉ์— ๋”ฐ๋ผ ๊ตฌ๋ถ„ํ–ˆ์—ˆ๋‹ค.

13 ๋ฒ„์ „๋ถ€ํ„ฐ๋Š” ์ปดํฌ๋„ŒํŠธ ํŒŒ์ผ ์ƒ๋‹จ์— use client๋ฅผ ์ž‘์„ฑํ•˜์—ฌ ๊ตฌ๋ถ„ํ•œ๋‹ค. ๊ธฐ๋ณธ์€ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋กœ, ์•„๋ฌด๊ฒƒ๋„ ๋ช…์‹œํ•˜์ง€ ์•Š์œผ๋ฉด ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋กœ ๋™์ž‘ํ•œ๋‹ค.

์ด๋ฅผ ์ฝ”๋“œ๋กœ ๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

TSX

1
2
3
4
5
6
// ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ (๋ช…์‹œํ•˜์ง€ ์•Š์•„๋„ ๋จ)

export default function Component(): ReactNode
{
    // ...
}

TSX

1
2
3
4
5
6
7
// ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ
'use client'

export default function Component(): ReactNode
{
    // ...
}

Next.js ์„ค์น˜ ์‹œ ๊ธฐ๋ณธ์ ์œผ๋กœ ํฌํ•จ๋˜๋Š” ESLint์˜ eslint-config-next ์„ค์ • ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ํ™œ์šฉํ•˜๋ฉด, ๊ฐ ์ปดํฌ๋„ŒํŠธ๋งˆ๋‹ค ๋ถˆ๊ฐ€๋Šฅํ•œ ๋กœ์ง์„ ์žก์•„์ค€๋‹ค. ์ด๋ฅผํ…Œ๋ฉด ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ์—์„œ useState, ๋ธŒ๋ผ์šฐ์ € ์ด๋ฒคํŠธ์˜ ์‚ฌ์šฉ์„ ๊ฐ์ง€ํ•˜๊ณ  ๊ฒฝ๊ณ ํ•˜๋Š” ์‹.

์ปดํฌ๋„ŒํŠธ์— ๋Œ€ํ•œ ์ž์„ธํ•œ ์ •๋ณด๋Š” ๐Ÿ”— Next.js 13 ๋ Œ๋”๋ง ๊ณต์‹๋ฌธ์„œ์—์„œ ํ™•์ธํ•˜์ž.

3. next/font์˜ ์ถ”๊ฐ€

์œ„ ๋‘ ๋ณ€๊ฒฝ์ ๊ณผ ๋‹ฌ๋ฆฌ, ์ด๊ฑด ์ถ”๊ฐ€๋œ ๊ธฐ๋Šฅ๊ฐ™์€๋ฐ, ํฐํŠธ ์ ์šฉ์˜ ํŽธ์˜์„ฑ์„ ๋†’์ธ ๊ธฐ๋Šฅ์ด๋‹ค. next/font๋ฅผ ํ™œ์šฉํ•˜๋ฉด, ๊ธฐ์กด์˜ ๋ฐฉ์‹์— ๋น„ํ•ด ํฐํŠธ๋ฅผ ์†์‰ฝ๊ฒŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์ง€์›ํ•˜๋Š” ๊ณต์‹ ์„œ๋น„์Šค๋Š” ์•„์ง ๐Ÿ”— Google Font ํ•˜๋‚˜๋‹ค. ๊ทธ ๋ฐ–์— ๋กœ์ปฌ ํฐํŠธํŒŒ์ผ์˜ ์—ฐ๊ฒฐ๋„ ์ง€์›ํ•œ๋‹ค.

3-1. Google Font ์‚ฌ์šฉํ•˜๊ธฐ

Google Font๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ์„ ์–ธํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

TSX

1
2
3
4
5
6
7
8
9
10
11
12
13
import { Noto_Sans_KRr } from 'next/font/google';

export const notoSans = Noto_Sans_KR({ subsets: [ 'latin' ], weight: [ '100', '300', '400', '500', '700', '900' ] });

export default function Component(): ReactNode
{
	return (
		<div>
            <div className={notoSans.className}>className ์ ์šฉ</div>
            <div style={{ fontFamily: notoSans.style.fontFamily }}>font-family ์ ์šฉ</div>
		</div>
	);
}

์œ„ ์ฝ”๋“œ๋Š” ์œ ๋ช…ํ•œ ํ•œ๊ธ€ ๊ธ€๊ผด ์ค‘ ํ•˜๋‚˜์ธ ๐Ÿ”— Noto Sans KR์„ ์ ์šฉํ•œ ์˜ˆ์‹œ๋‹ค.

className์œผ๋กœ ์ ์šฉํ•˜๋Š” ๋ฐฉ์‹๊ณผ font-family๋กœ ์ ์šฉํ•˜๋Š” ๋ฐฉ์‹ ๋‘ ๊ฐ€์ง€๊ฐ€ ์žˆ๋‹ค.

ํฐํŠธ ํŒŒ์ผ์„ ๋กœ์ปฌ ํ˜น์€ CDN์œผ๋กœ ๋ฐ›์•„ CSS๋ฅผ ์ ์šฉํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ํ›จ์”ฌ ๊ฐ„๋‹จํ•˜์—ฌ, Google Font์—์„œ ์›ํ•˜๋Š” ํฐํŠธ๋ฅผ ๊ณ ๋ฅด๊ณ  ์ด๋ฅผ next/font๋กœ ์ฐพ์•„ ์ ์šฉํ•˜๋ฉด ๋œ๋‹ค.

3-2. ๋กœ์ปฌ ํฐํŠธ ์‚ฌ์šฉํ•˜๊ธฐ

next/font์˜ ๊ฐ€์žฅ ํฐ ๋‹จ์ ์€ Google Font ์ด์™ธ์— ์ง€์›ํ•˜๋Š” ์„œ๋น„์Šค๊ฐ€ ์•„์ง ์—†๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ๋‹คํ–‰ํžˆ, ๋กœ์ปฌ ํฐํŠธ๋„ ์ง€์›ํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์—, Google Font์— ๋“ฑ๋ก๋˜์ง€ ์•Š์€ ํฐํŠธ๋„ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

TSX

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import localFont from 'next/font/local';

const pretendard = localFont({
    src: [
        {
            path: './pretendard-regular.otf',
            weight: 'normal',
            style: 'normal',
        },
        {
            path: './pretendard-bold.otf',
            weight: 'bold',
            style: 'normal',
        },
        {
            path: './pretendard-italic.otf',
            weight: 'normal',
            style: 'italic',
        },
    ],
});

export default function Component(): ReactNode
{
	return (
		<div>
            <div className={pretendard.className}>className ์ ์šฉ</div>
            <div style={{ fontFamily: pretendard.style.fontFamily }}>font-family ์ ์šฉ</div>
		</div>
	);
}

์œ„์™€ ๊ฐ™์ด ํฐํŠธ์˜ ๊ฒฝ๋กœ์— ์ง์ ‘ ์ ‘๊ทผํ•˜์—ฌ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

ํฐํŠธ์— ๋Œ€ํ•œ ๋”์šฑ ์ž์„ธํ•œ ์ •๋ณด๋Š” ๐Ÿ”— Next.js 13 ํฐํŠธ ๊ณต์‹๋ฌธ์„œ์—์„œ ํ™•์ธํ•˜์ž.


๐Ÿท๏ธ ํƒœ๊ทธ
# React
# Web
# Next.js

์ฝ์–ด์ฃผ์…”์„œ ๊ณ ๋งˆ์›Œ์š”!

๋„์›€์ด ๋˜์…จ๋‹ค๋ฉด, ๊ณต๊ฐ์ด๋‚˜ ๋Œ“๊ธ€์„ ๋‹ฌ์•„์ฃผ์‹œ๋Š” ๊ฑด ์–ด๋–ค๊ฐ€์š”?

๋ธ”๋กœ๊ทธ ์šด์˜์— ํฐ ํž˜์ด ๋ฉ๋‹ˆ๋‹ค.

https://hits.seeyoufarm.com/api/count/incr/badge.svg?count_bg=%23484848&icon=react.svg&icon_color=dodgerblue&title=view&title_bg=%23242424&url=https%3A%2F%2Fblog.itcode.dev%2Fposts%2F2023%2F09%2F23%2Fnextjs13