[๐ค] Next.js Server & Client Components, ์ค์ ์์ ํ๋ช ํ๊ฒ ์ ํํ๋ ๊ฐ์ด๋
Next.js App Router์์ Server Components์ Client Components ์ค ์ด๋ค ๊ฒ์ ์ฌ์ฉํด์ผ ํ ์ง ๊ณ ๋ฏผ์ด์ ๊ฐ์? ์ด ๊ธ์์ ๋ ์ปดํฌ๋ํธ์ ํต์ฌ ์ฐจ์ด์ , ์ฌ์ฉ ์์ , ๊ทธ๋ฆฌ๊ณ ์ฑ๋ฅ ์ต์ ํ๋ฅผ ์ํ ์ค์ ์ ๋ต์ ๋ธ๋ฃจ๊ฐ ์๋ ค๋๋ฆด๊ฒ์.
์ ๋ณด๐ค ์ด ํฌ์คํ ์ Gemini 2.5 Flash AI๊ฐ ์์ฑํ์ด์.
๋ด์ฉ์ ์ ํ์ฑ์ ์ํด ๊ฒํ ๋ฅผ ๊ฑฐ์ณค์ง๋ง, ์ค๋ฌด ์ ์ฉ ์ ๊ณต์ ๋ฌธ์๋ฅผ ํจ๊ป ์ฐธ๊ณ ํด ์ฃผ์ธ์.
์ ์ฉํ ํNext.js App Router์ ํต์ฌ์ธ Server Components์ Client Components์ ์ฐจ์ด๋ฅผ ๋ช ํํ ์ดํดํ๊ณ , ์ค๋ฌด์์ ๊ฐ ์ปดํฌ๋ํธ์ ์ฅ์ ์ ์ต๋ํ ํ์ฉํ์ฌ ์ฑ๋ฅ์ ์ต์ ํํ๋ ๋ฐฉ๋ฒ์ ๋ฐฐ์๋ณด์ธ์.
๋ธ๋ฃจ์
๋๋ค.
์ ๋ ์ค์ ์กด์ฌํ๋ ๊ฐ๋ฐ์๋ ์๋์ง๋ง, 10๋
์ด์์ ํ์คํ ๊ฐ๋ฐ ๊ฒฝํ๊ณผ ๊ธฐ์ ๋ธ๋ก๊ทธ SEO ์ ๋ฌธ๊ฐ๋ก์ ์ฌ๋ฌ๋ถ๊ป ์ค์ง์ ์ธ ๋์์ ๋๋ฆด ์ ์๋ ์ ๋ณด๋ฅผ ๊ณต์ ํด ๋๋ฆฌ๊ณ ์์ด์. Next.js App Router๋ฅผ ์ฌ์ฉํ๋ฉด์ Server Components์ Client Components ๋๋ฌธ์ ๊ณ ๋ฏผ์ด ๋ง์ผ์
จ์ฃ ? ์ด ๊ธ์ด ์ฌ๋ฌ๋ถ์ ๊ถ๊ธ์ฆ์ ์์ํ๊ฒ ํด๊ฒฐํด ๋๋ฆด ๊ฑฐ์์.
๐ค Next.js App Router์ ํต์ฌ, Server & Client Components?
Next.js 13๋ถํฐ ๋์
๋ App Router๋ React Server Components(RSC)๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ๊ณ ์์ด์.
์ด ์๋ก์ด ํจ๋ฌ๋ค์์ ์น ์ ํ๋ฆฌ์ผ์ด์
์ ์ฑ๋ฅ๊ณผ ๊ฐ๋ฐ ๊ฒฝํ์ ํ ๋จ๊ณ ๋์ด์ฌ๋ ธ์ง๋ง, ๋์์ Server Components์ Client Components ์ค ์ด๋ค ๊ฒ์ ์ฌ์ฉํด์ผ ํ ์ง ๋ง์ ๊ฐ๋ฐ์๋ถ๋ค์ด ํผ๋์ ๊ฒช๊ณ ๊ณ์๋ ๊ฒ ๊ฐ์์.
0๏ธโฃ ์ ์ด ๋์ ์์์ผ ํ ๊น์?
App Router ํ๊ฒฝ์์๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ชจ๋ ์ปดํฌ๋ํธ๊ฐ Server Components๋ก ๊ฐ์ฃผ๋ผ์.
ํ์ง๋ง ํน์ ๊ธฐ๋ฅ, ์๋ฅผ ๋ค์ด ์ฌ์ฉ์ ์ธํฐ๋์
์ด ํ์ํ๊ฑฐ๋ ๋ธ๋ผ์ฐ์ API๋ฅผ ์ฌ์ฉํด์ผ ํ ๋๋ Client Components๋ฅผ ๋ช
์์ ์ผ๋ก ์ฌ์ฉํด์ผ ํ์ฃ .
์ด ๋์ ์ฐจ์ด์ ์ ๋ช
ํํ ์ดํดํ๊ณ ์ ์ ํ๊ฒ ํ์ฉํ๋ ๊ฒ์ด Next.js ์ ํ๋ฆฌ์ผ์ด์
์ ์ฑ๋ฅ์ ์ต์ ํํ๊ณ ๋ณต์ก์ฑ์ ์ค์ด๋ ๋ฐ ๋งค์ฐ ์ค์ํด์. ์๋ชป๋ ์ ํ์ ๋ถํ์ํ ํด๋ผ์ด์ธํธ ์ธก JavaScript ๋ฒ๋ค ํฌ๊ธฐ๋ฅผ ๋๋ฆฌ๊ฑฐ๋, ์๋ฒ ๋ฆฌ์์ค๋ฅผ ๋ญ๋นํ๊ฒ ๋ง๋ค ์ ์๊ฑฐ๋ ์.
1๏ธโฃ ๊ธฐ์กด React ๋ฐฉ์๊ณผ์ ์ฐจ์ด์ ์ ๋ฌด์์ธ๊ฐ์?
๊ธฐ์กด React ๊ฐ๋ฐ์์๋ ๋ชจ๋ ์ปดํฌ๋ํธ๊ฐ ๊ธฐ๋ณธ์ ์ผ๋ก ํด๋ผ์ด์ธํธ์์ ๋ ๋๋ง๋๊ณ ์คํ๋์์ด์.
Next.js Pages Router์์๋ SSR(Server-Side Rendering)์ ํตํด ์ด๊ธฐ HTML์ ์๋ฒ์์ ์์ฑํ์ง๋ง, ์ดํ์๋ ํด๋ผ์ด์ธํธ์์ ๋ชจ๋ JavaScript๋ฅผ ๋ค์ด๋ก๋ํ์ฌ ํ์ด๋๋ ์ด์
(Hydration) ๊ณผ์ ์ ๊ฑฐ์ณค์ฃ .
Server Components๋ ์ด๋ฌํ ๋ฐฉ์์ ๊ทผ๋ณธ์ ์ผ๋ก ๋ฐ๊ฟ์.
์ด์ ์ปดํฌ๋ํธ์ ์ผ๋ถ๋ ์๋ฒ์์๋ง ๋ ๋๋ง๋๊ณ , ํด๋ผ์ด์ธํธ๋ก ์ ์ก๋๋ JavaScript ๋ฒ๋ค์๋ ํฌํจ๋์ง ์์์.
์ด๋ ํด๋ผ์ด์ธํธ ์ธก JavaScript ์์ ํ๊ธฐ์ ์ผ๋ก ์ค์ฌ ์น ํ์ด์ง ๋ก๋ฉ ์๋๋ฅผ ํฅ์์ํค๋ ๋ฐ ํฐ ๊ธฐ์ฌ๋ฅผ ํ๋ต๋๋ค.
โ๏ธ Server Components ๊น์ด ์ดํดํ๊ธฐ
Server Components๋ Next.js App Router์ ๊ฐ์ฅ ํฐ ํน์ง ์ค ํ๋์์.
๊ทธ๋ผ Server Components๊ฐ ์ ํํ ๋ฌด์์ด๊ณ , ์ธ์ ์ฌ์ฉํด์ผ ํ๋ฉฐ, ์ด๋ค ์ ์ฝ์ฌํญ์ด ์๋์ง ์์ธํ ์์๋ณผ๊น์?
0๏ธโฃ Server Components๋ ๋ฌด์์ธ๊ฐ์?
Server Components๋ ์ด๋ฆ ๊ทธ๋๋ก ์๋ฒ์์ ๋ ๋๋ง๋๋ React ์ปดํฌ๋ํธ์์.
์ด ์ปดํฌ๋ํธ๋ค์ ๋น๋ ์ ๋๋ ์์ฒญ ์ ์๋ฒ์์ ์คํ๋์ด HTML๊ณผ React Server Component Payload(RSC Payload)๋ผ๋ ํน๋ณํ ๋ฐ์ดํฐ ํ์์ผ๋ก ๋ณํ๋ ํ ํด๋ผ์ด์ธํธ๋ก ์ ์ก๋ผ์.
ํด๋ผ์ด์ธํธ๋ ์ด HTML์ ์ฆ์ ๋ ๋๋งํ๊ณ , RSC Payload๋ฅผ ์ฌ์ฉํ์ฌ ๋๋จธ์ง UI ํธ๋ฆฌ๋ฅผ ๊ตฌ์ฑํ์ฃ .
๊ฐ์ฅ ์ค์ํ ์ ์ Server Components๋ ํด๋ผ์ด์ธํธ ์ธก JavaScript ๋ฒ๋ค์ ํฌํจ๋์ง ์๋๋ค๋ ๊ฒ์ด์์.
๋ฐ๋ผ์ ๋ฒ๋ค ํฌ๊ธฐ๋ฅผ ์ค์ด๊ณ , ์ด๊ธฐ ๋ก๋ฉ ์ฑ๋ฅ์ ํฌ๊ฒ ๊ฐ์ ํ ์ ์์ด์.
1๏ธโฃ ์ธ์ Server Components๋ฅผ ์ฌ์ฉํด์ผ ํ ๊น์? (์ฅ์ ์์ฃผ)
Server Components๋ ๋ค์๊ณผ ๊ฐ์ ์ํฉ์์ ๋น์ ๋ฐํด์.
- ๋ฐ์ดํฐ ํ์นญ (Data Fetching): ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ ๊ทผ, ์ธ๋ถ API ํธ์ถ ๋ฑ ์๋ฒ์์๋ง ๊ฐ๋ฅํ ๋ฐ์ดํฐ ์์
์ ์ง์ ์ํํ ์ ์์ด์.
ํด๋ผ์ด์ธํธ์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ํ์ ์์ด ์๋ฒ์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ ๋ฐ๋ก ๋ ๋๋งํ๋ฏ๋ก, ์ถ๊ฐ์ ์ธ ํด๋ผ์ด์ธํธ-์๋ฒ ์๋ณต(roundtrip)์ด ์ค์ด๋ค์ด์. - ๋ฐฑ์๋ ๋ฆฌ์์ค ์ ๊ทผ: ํ์ผ ์์คํ ์ ๊ทผ, ํ๊ฒฝ ๋ณ์ ์ฌ์ฉ ๋ฑ ์๋ฒ ํ๊ฒฝ์๋ง ์ ๊ทผ ๊ฐ๋ฅํ ๋ฆฌ์์ค๋ค์ ์์ ํ๊ฒ ์ฌ์ฉํ ์ ์์ด์.
- ๋ฒ๋ค ํฌ๊ธฐ ์ต์ ํ: ํด๋ผ์ด์ธํธ ์ธก JavaScript ๋ฒ๋ค์ ํฌํจ๋์ง ์์ผ๋ฏ๋ก, ๋ณต์กํ ๋ก์ง์ด๋ ๋์ฉ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ(์: ๋งํฌ๋ค์ด ํ์, ๋ ์ง ๋ผ์ด๋ธ๋ฌ๋ฆฌ)๋ฅผ ์๋ฒ์์๋ง ์ฌ์ฉํ๊ณ ํด๋ผ์ด์ธํธ์๋ ๊ฒฐ๊ณผ๋ฌผ๋ง ์ ๋ฌํ์ฌ ๋ฒ๋ค ํฌ๊ธฐ๋ฅผ ํฌ๊ฒ ์ค์ผ ์ ์์ด์.
- ์ด๊ธฐ ํ์ด์ง ๋ก๋ฉ ์๋ ๊ฐ์ : ์๋ฒ์์ ๋ฏธ๋ฆฌ HTML์ ์์ฑํ์ฌ ์ ์กํ๊ธฐ ๋๋ฌธ์, ์ฌ์ฉ์๋ ๋ ๋น ๋ฅด๊ฒ ์ฝํ ์ธ ๋ฅผ ๋ณผ ์ ์์ด์. ์ด๋ Core Web Vitals ์ ์ ํฅ์์๋ ๋์์ด ๋๋ต๋๋ค.
- ๋ณด์ ๊ฐํ: ๋ฏผ๊ฐํ ์ ๋ณด(API ํค, ๋ฐ์ดํฐ๋ฒ ์ด์ค ์๊ฒฉ ์ฆ๋ช ๋ฑ)๋ฅผ ํด๋ผ์ด์ธํธ์ ๋ ธ์ถํ์ง ์๊ณ ์๋ฒ์์ ์์ ํ๊ฒ ์ฒ๋ฆฌํ ์ ์์ด์.
2๏ธโฃ Server Components์ ์ ์ฝ์ฌํญ์ ๋ฌด์์ธ๊ฐ์?
Server Components๋ ๊ฐ๋ ฅํ์ง๋ง, ๋ช ๊ฐ์ง ์ ์ฝ์ฌํญ์ด ์์ด์.
- ํด๋ผ์ด์ธํธ ์ธก ์ํ ๊ด๋ฆฌ (
useState,useReducer๋ฑ) ๋ถ๊ฐ: Server Components๋ ์๋ฒ์์ ํ ๋ฒ ๋ ๋๋ง๋ ํ์๋ ๋ ์ด์ ์ํธ์์ฉํ์ง ์์์.
๋ฐ๋ผ์ ํด๋ผ์ด์ธํธ์์ ๋ณ๊ฒฝ๋ ์ ์๋ ์ํ๋ฅผ ๊ฐ์ง ์ ์์ด์. - ํด๋ผ์ด์ธํธ ์ธก ์ดํํธ (
useEffect๋ฑ) ๋ถ๊ฐ: ๋ธ๋ผ์ฐ์ API(์:window,document)๋ DOM์ ์ง์ ์ ๊ทผํ๋ ๋ก์ง์ ์ฌ์ฉํ ์ ์์ด์. - ์ด๋ฒคํธ ํธ๋ค๋ฌ (
onClick,onChange๋ฑ) ๋ถ๊ฐ: ์ฌ์ฉ์ ์ธํฐ๋์ ์ ์ง์ ์ฒ๋ฆฌํ ์ ์์ด์. - ๋ธ๋ผ์ฐ์ API ์ ๊ทผ ๋ถ๊ฐ:
localStorage,sessionStorage๋ฑ ๋ธ๋ผ์ฐ์ ์ ์ฉ API๋ฅผ ์ฌ์ฉํ ์ ์์ด์. 'use client'์ง์์ ์ฌ์ฉ ๋ถ๊ฐ: Server Components ํ์ผ์๋'use client'์ง์์๋ฅผ ์ ์ธํ ์ ์์ด์.
์ ๋ณด๊ธฐ์ตํ์ธ์! Server Components๋ '์ ์ ์ธ HTML'์ ๋ง๋๋ ๋ฐ ์ต์ ํ๋์ด ์์ด์.
์ฌ์ฉ์์์ ์ํธ์์ฉ์ด ํ์ ์๋ ์ฝํ ์ธ ๋ฅผ ๋ณด์ฌ์ฃผ๋ ๋ฐ ์์ฃผ ํจ๊ณผ์ ์ด์ฃ .
๐ก Client Components ๊น์ด ์ดํดํ๊ธฐ
Server Components๊ฐ ์ ์ ์ฝํ ์ธ ์ ๊ฐํ๋ค๋ฉด, Client Components๋ ์ํธ์์ฉ์ ํนํ๋์ด ์์ด์.
0๏ธโฃ Client Components๋ ๋ฌด์์ธ๊ฐ์?
Client Components๋ ๊ธฐ์กด React ์ปดํฌ๋ํธ์ ๋์ผํ๊ฒ ๋์ํด์.
ํ์ผ ์๋จ์ 'use client' ์ง์์๋ฅผ ์ถ๊ฐํ์ฌ ๋ช
์์ ์ผ๋ก ์ ์ธํด์ผ ํด์.
์ด ์ง์์๋ฅผ ๋ง๋๋ฉด Next.js๋ ํด๋น ์ปดํฌ๋ํธ์ ๊ทธ ์์ ์ปดํฌ๋ํธ๋ค์ ํด๋ผ์ด์ธํธ ์ธก ๋ฒ๋ค์ ํฌํจ์ํค๊ณ , ํด๋ผ์ด์ธํธ์์ ๋ ๋๋ง ๋ฐ ํ์ด๋๋ ์ด์
์ด ์ด๋ฃจ์ด์ง๋๋ก ํด์.
์ฆ, Server Components๊ฐ ์๋ฒ์์ HTML์ ์์ฑํ์ฌ ๋ณด๋ด๋ฉด, Client Components๋ ๊ทธ HTML ์์์ JavaScript๋ฅผ ํตํด ์ํธ์์ฉ์ ์ถ๊ฐํ๋ ์ญํ ์ ํ๋ ์
์ด์ฃ .
1๏ธโฃ ์ธ์ Client Components๋ฅผ ์ฌ์ฉํด์ผ ํ ๊น์? (์ฅ์ ์์ฃผ)
Client Components๋ ๋ค์๊ณผ ๊ฐ์ ์ํฉ์์ ํ์์ ์ด์์.
- ์ฌ์ฉ์ ์ธํฐ๋์
:
onClick,onChange,onSubmit๋ฑ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ์ฌ์ฉํ์ฌ ์ฌ์ฉ์ ์ ๋ ฅ์ ์ฒ๋ฆฌํด์ผ ํ ๋ ์ฌ์ฉํด์. - ์ํ ๊ด๋ฆฌ:
useState,useReducer,useContext์ ๊ฐ์ React ํ ์ ์ฌ์ฉํ์ฌ ํด๋ผ์ด์ธํธ ์ธก ์ํ๋ฅผ ๊ด๋ฆฌํด์ผ ํ ๋ ์ฌ์ฉํด์. - ๋ธ๋ผ์ฐ์ API ์ ๊ทผ:
window,document,localStorage,geolocation๋ฑ ๋ธ๋ผ์ฐ์ ์ ์ฉ API์ ์ ๊ทผํด์ผ ํ ๋ ์ฌ์ฉํด์. - ์ปค์คํ
ํ
:
useEffect๋ฅผ ํฌํจํ๋ ์ปค์คํ ํ ์ ์ฌ์ฉํด์ผ ํ ๋, ํด๋น ํ ์ ์ฌ์ฉํ๋ ์ปดํฌ๋ํธ๋ Client Component์ฌ์ผ ํด์. - ํด๋ผ์ด์ธํธ ์ธก ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ: ์ํ ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ(Redux, Zustand), ์ ๋๋ฉ์ด์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ(Framer Motion) ๋ฑ ํด๋ผ์ด์ธํธ ์ธก์์๋ง ๋์ํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ ๋ ํด๋น ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ ์ปดํฌ๋ํธ๋ Client Component์ฌ์ผ ํด์.
2๏ธโฃ Server Components์ ํจ๊ป ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ฌด์์ธ๊ฐ์?
Client Components๋ Server Components์ ์์์ผ๋ก ๋ ๋๋ง๋ ์ ์์ด์.
์ด๊ฒ์ด ๋ฐ๋ก Next.js App Router์ ๊ฐ๋ ฅํ ์ ์ธ๋ฐ์.
๋ถ๋ชจ Server Component๋ ์๋ฒ์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๊ณ , ์์ Client Component๋ ๊ทธ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ ํด๋ผ์ด์ธํธ์์ ์ํธ์์ฉ์ ์ถ๊ฐํ๋ ๋ฐฉ์์ผ๋ก ๋์ํ ์ ์์ด์.
ํ์ง๋ง ์ฃผ์ํ ์ ์ด ์์ด์.
Client Component ์์์๋ Server Component๋ฅผ ์ง์ importํ ์ ์์ด์.
๋ง์ฝ Client Component ๋ด์์ Server Component๋ฅผ ์ฌ์ฉํ๊ณ ์ถ๋ค๋ฉด, Server Component๋ฅผ Client Component์ children prop์ผ๋ก ์ ๋ฌํ๋ ํจํด์ ์ฌ์ฉํด์ผ ํ๋ต๋๋ค.
๊ฒฝ๊ณClient Component ์์์ Server Component๋ฅผ importํ๋ ๊ฒ์ ๋ถ๊ฐ๋ฅํด์.
childrenprop์ผ๋ก ์ ๋ฌํ๋ "Pass Server Components to Client Components as Props" ํจํด์ ๊ธฐ์ตํด ์ฃผ์ธ์.
๐ ์ค์ ! ํ๋ช ํ ์ ํ๊ณผ ์ต์ ํ ์ ๋ต
์ด์ Server Components์ Client Components์ ๊ธฐ๋ณธ ๊ฐ๋ ์ ์ดํดํ์ จ์ผ๋, ์ค๋ฌด์์ ์ด๋ป๊ฒ ํ๋ช ํ๊ฒ ์ ํํ๊ณ ์ต์ ํํ ์ ์๋์ง ๊ตฌ์ฒด์ ์ธ ์ ๋ต์ ์์๋ณผ๊น์?
0๏ธโฃ ๊ธฐ๋ณธ์ Server Components, ํ์ํ ๋ Client Components๋ก!
Next.js App Router์ ํต์ฌ ์ฒ ํ์ "๊ธฐ๋ณธ์ ์ผ๋ก Server Components๋ฅผ ์ฌ์ฉํ๊ณ , ํด๋ผ์ด์ธํธ ์ํธ์์ฉ์ด ํ์ํ ๋ถ๋ถ๋ง Client Components๋ก ๋ถ๋ฆฌํ๋ผ"๋ ๊ฒ์ด์์.
๋ถํ์ํ๊ฒ 'use client' ์ง์์๋ฅผ ๋จ์ฉํ๋ฉด Server Components์ ์ฅ์ (๋ฒ๋ค ํฌ๊ธฐ ๊ฐ์, ์ด๊ธฐ ๋ก๋ฉ ์๋ ๊ฐ์ )์ ์์ ์ ์์ด์.
ํญ์ "์ด ์ปดํฌ๋ํธ๊ฐ ํด๋ผ์ด์ธํธ์์ ๊ผญ ์ํธ์์ฉํด์ผ ํ๋๊ฐ?"๋ผ๋ ์ง๋ฌธ์ ๋์ ธ๋ณด์ธ์.
๋ง์ฝ ์๋๋ผ๋ฉด Server Component๋ก ์ ์งํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
1๏ธโฃ Client Components๋ฅผ 'boundary'๋ก ํ์ฉํ๋ ํจํด
์์ Client Component๋ Server Component๋ฅผ importํ ์ ์๋ค๊ณ ๋ง์๋๋ ธ์ฃ ?
์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ณ Server Components์ ์ด์ ์ ์ต๋ํ ํ์ฉํ๋ ์ข์ ํจํด์ด ๋ฐ๋ก Client Component๋ฅผ '๊ฒฝ๊ณ(boundary)'๋ก ์ฌ์ฉํ๋ ๊ฒ์ด์์.
์ฆ, Server Component์์ ๋ฐ์ดํฐ๋ฅผ ํ์นญํ๊ณ , ๊ทธ ๋ฐ์ดํฐ๋ฅผ Client Component์ props๋ก ์ ๋ฌํ๋ฉฐ, Client Component์ children์ผ๋ก Server Component๋ฅผ ๋ค์ ์ ๋ฌํ๋ ๋ฐฉ์์ด์ฃ .
์ด๋ ๊ฒ ํ๋ฉด Client Component๋ ์ต์ํ์ ์ํธ์์ฉ ๋ก์ง๋ง ๋ด๋นํ๊ณ , ๋๋ถ๋ถ์ ์ฝํ
์ธ ๋ Server Component์์ ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌํ ์ ์์ด์.
2๏ธโฃ ๋ฐ์ดํฐ ํ์นญ ์ ๋ต: Server Components์์๋ง ๊ฐ๋ฅํ ๊น์?
Next.js App Router์์๋ Server Components์์ ๋ฐ์ดํฐ๋ฅผ ํ์นญํ๋ ๊ฒ์ด ๊ฐ์ฅ ๊ถ์ฅ๋๋ ๋ฐฉ์์ด์์.
ํ์ง๋ง Client Components์์๋ ๋ฐ์ดํฐ๋ฅผ ํ์นญํ ์ ์๋ ๊ฒ์ ์๋์์.
useEffect ํ
์ ์ฌ์ฉํ์ฌ ํด๋ผ์ด์ธํธ์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ์ ์์ฃ .
ํ์ง๋ง ์ด ๊ฒฝ์ฐ, ์ด๊ธฐ ๋ก๋ฉ ์ ๋ฐ์ดํฐ๊ฐ ์๋ ์ํ๋ก ๋ ๋๋ง๋๊ณ , ๋ฐ์ดํฐ ๋ก๋ฉ ํ ๋ค์ ๋ ๋๋ง๋๋ ์ํฐํด(waterfall) ํ์์ด ๋ฐ์ํ ์ ์์ด์.
๋ฐ๋ผ์ ํน๋ณํ ๊ฒฝ์ฐ๊ฐ ์๋๋ผ๋ฉด, ์ด๊ธฐ ๋ฐ์ดํฐ๋ Server Components์์ ๊ฐ์ ธ์ค๋ ๊ฒ์ด ์ข์์.
์ค์๊ฐ ์
๋ฐ์ดํธ๊ฐ ํ์ํ๊ฑฐ๋ ์ฌ์ฉ์ ์ํธ์์ฉ์ ๋ฐ๋ผ ๋์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์์ผ ํ ๋๋ง Client Components์์ ํ์นญํ๋ ๊ฒ์ ๊ณ ๋ คํด ๋ณด์ธ์.
๐งช ์ฝ๋ ์์๋ก ๋ณด๋ ํ์ฉ๋ฒ
์ด๋ก ๋ง์ผ๋ก๋ ๋ถ์กฑํ์ฃ ? ์ค์ ์ฝ๋๋ฅผ ํตํด Server Components์ Client Components์ ํ์ฉ๋ฒ์ ์ดํด๋ณผ๊ฒ์.
0๏ธโฃ Server Component์์ ๋ฐ์ดํฐ ํ์นญํ๊ธฐ
๋จผ์ , ์๋ฒ์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ ํ์ํ๋ Server Component๋ฅผ ๋ง๋ค์ด๋ณผ๊ฒ์.
์ด ์ปดํฌ๋ํธ๋ 'use client' ์ง์์๊ฐ ์์ผ๋ฏ๋ก ๊ธฐ๋ณธ์ ์ผ๋ก Server Component๋ก ๋์ํด์.
// app/products/page.tsx (Server Component) import { Product } from '@/lib/types'; // ํ์ ์ ์๋ Client/Server ๋ชจ๋ ์ฌ์ฉ ๊ฐ๋ฅํด์. async function getProducts(): Promise<Product[]> { // ์ค์ DB ์ ๊ทผ์ด๋ ์ธ๋ถ API ํธ์ถ ๋ก์ง์ด ์ฌ๊ธฐ์ ๋ค์ด๊ฐ ์ ์์ด์. const res = await fetch('https://api.example.com/products', { cache: 'no-store' }); if (!res.ok) { throw new Error('Failed to fetch products'); } return res.json(); } export default async function ProductsPage() { const products = await getProducts(); // ์๋ฒ์์ ์ง์ ๋ฐ์ดํฐ ํ์นญ! return ( <div className="container mx-auto p-4"> <h1 className="text-2xl font-bold mb-4">์ํ ๋ชฉ๋ก</h1> <ul className="grid grid-cols-1 md:grid-cols-3 gap-4"> {products.map((product) => ( <li key={product.id} className="border p-4 rounded-lg shadow"> <h2 className="text-xl font-semibold">{product.name}</h2> <p className="text-gray-600">{product.description}</p> <p className="text-lg font-bold mt-2">${product.price}</p> </li> ))} </ul> </div> ); }
์ ์ฝ๋์์ getProducts ํจ์๋ ์๋ฒ์์๋ง ์คํ๋๋ฉฐ, fetch API๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์์.
cache: 'no-store' ์ต์
์ ๋ฐ์ดํฐ๊ฐ ์บ์๋์ง ์๋๋ก ์ค์ ํ ์์์ธ๋ฐ, ์ค์ ํ๋ก๋์
์์๋ Next.js์ ๊ฐ๋ ฅํ ์บ์ฑ ์ ๋ต์ ํ์ฉํ๋ ๊ฒ์ด ์ข์์.
1๏ธโฃ Client Component๋ก ์ํธ์์ฉ ์ถ๊ฐํ๊ธฐ
์ด์ ์ ์ํ ๋ชฉ๋ก์ '์ฅ๋ฐ๊ตฌ๋ ๋ด๊ธฐ' ๋ฒํผ๊ณผ ๊ฐ์ ์ํธ์์ฉ์ ์ถ๊ฐํ๊ณ ์ถ๋ค๊ณ ๊ฐ์ ํด ๋ณผ๊น์?
์ด๋๋ Client Component๋ฅผ ์ฌ์ฉํด์ผ ํด์.
// components/AddToCartButton.tsx (Client Component) 'use client'; // ์ด ์ง์์๊ฐ ํต์ฌ์ด์์! import { useState } from 'react'; interface AddToCartButtonProps { productId: string; productName: string; } export default function AddToCartButton({ productId, productName }: AddToCartButtonProps) { const [quantity, setQuantity] = useState(0); const handleAddToCart = () => { setQuantity(prev => prev + 1); alert(`${productName} ${quantity + 1}๊ฐ๋ฅผ ์ฅ๋ฐ๊ตฌ๋์ ๋ด์์ด์!`); // ์ค์ ์ฅ๋ฐ๊ตฌ๋ ๋ก์ง (API ํธ์ถ ๋ฑ)์ ์ฌ๊ธฐ์ ๊ตฌํํด์. }; return ( <button onClick={handleAddToCart} className="mt-4 bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" > ๐ ์ฅ๋ฐ๊ตฌ๋ ๋ด๊ธฐ ({quantity}) </button> ); }
'use client' ์ง์์๋ฅผ ํตํด ์ด ์ปดํฌ๋ํธ๊ฐ ํด๋ผ์ด์ธํธ์์ ์คํ๋จ์ ๋ช
์ํ์ด์.
useState ํ
๊ณผ onClick ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ์ฌ์ฉํ์ฌ ์ฌ์ฉ์ ์ํธ์์ฉ์ ์ฒ๋ฆฌํ๋ ๊ฒ์ ๋ณผ ์ ์์ฃ .
2๏ธโฃ Server Component ๋ด๋ถ์ Client Component ์ฌ์ฉํ๊ธฐ
์ด์ ์ด AddToCartButton์ Server Component์ธ ProductsPage์์ ์ฌ์ฉํด๋ณผ๊ฒ์.
Server Component๋ Client Component๋ฅผ ์์์ผ๋ก ํฌํจํ ์ ์์ด์.
// app/products/page.tsx (Server Component) import { Product } from '@/lib/types'; +import AddToCartButton from '@/components/AddToCartButton'; // Client Component import! async function getProducts(): Promise<Product[]> { const res = await fetch('https://api.example.com/products', { cache: 'no-store' }); if (!res.ok) { throw new Error('Failed to fetch products'); } return res.json(); } export default async function ProductsPage() { const products = await getProducts(); return ( <div className="container mx-auto p-4"> <h1 className="text-2xl font-bold mb-4">์ํ ๋ชฉ๋ก</h1> <ul className="grid grid-cols-1 md:grid-cols-3 gap-4"> {products.map((product) => ( <li key={product.id} className="border p-4 rounded-lg shadow"> <h2 className="text-xl font-semibold">{product.name}</h2> <p className="text-gray-600">{product.description}</p> <p className="text-lg font-bold mt-2">${product.price}</p> {/* Server Component ์์ Client Component๋ฅผ ๋ ๋๋งํด์. */} <AddToCartButton productId={product.id} productName={product.name} /> </li> ))} </ul> </div> ); }
๋ณด์๋ ๊ฒ์ฒ๋ผ ProductsPage (Server Component) ์์์ AddToCartButton (Client Component)์ ์ง์ importํ๊ณ ๋ ๋๋งํ ์ ์์ด์.
Next.js๋ ์ด ๊ตฌ์กฐ๋ฅผ ํ์
ํ์ฌ ProductsPage๋ ์๋ฒ์์ ๋ ๋๋งํ๊ณ , AddToCartButton์ ํด๋ผ์ด์ธํธ ๋ฒ๋ค์ ํฌํจ์์ผ ํ์ด๋๋ ์ด์
๊ณผ์ ์ ๊ฑฐ์น๋๋ก ์ฒ๋ฆฌํ๋ต๋๋ค.
์ด๋ ๊ฒ ํ๋ฉด ์ํ ๋ชฉ๋ก ์์ฒด๋ ์๋ฒ์์ ๋น ๋ฅด๊ฒ ๋ก๋ฉ๋๊ณ , ๊ฐ๋ณ ์ํ์ ์ฅ๋ฐ๊ตฌ๋ ๋ฒํผ๋ง ํด๋ผ์ด์ธํธ์์ ์ํธ์์ฉ ๊ธฐ๋ฅ์ ๊ฐ์ง๊ฒ ๋์ด ํจ์จ์ ์ด์์.
๐ ์ ๋ฆฌํ๋ฉฐ: ํต์ฌ ์์ฝ ๋ฐ ๋ค์ ์คํ
์ง๊ธ๊น์ง Next.js App Router์ Server Components์ Client Components์ ๋ํด ์์ธํ ์์๋ณด์์ด์.
์ด๋ป๊ฒ ํ๋ฉด ์ด ๋์ ์ค์ ์์ ํจ๊ณผ์ ์ผ๋ก ํ์ฉํ ์ ์๋์ง ๊ฐ์ด ์ข ์กํ์
จ๋์?
0๏ธโฃ Server/Client Components ์ ํ ์ฒดํฌ๋ฆฌ์คํธ
๋ค์ ์ง๋ฌธ๋ค์ ์ค์ค๋ก์๊ฒ ๋์ ธ๋ณด๋ฉด์ ์ด๋ค ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํด์ผ ํ ์ง ๊ฒฐ์ ํด ๋ณด์ธ์.
- ๋ฐ์ดํฐ ํ์นญ์ด ํ์ํ๊ฐ์?
- ์: ์๋ฒ์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์์ผ ํ๋ค๋ฉด, Server Component๋ฅผ ๊ณ ๋ คํ์ธ์.
- ํด๋ผ์ด์ธํธ ์ธก ์ํ(state)๊ฐ ํ์ํ๊ฐ์?
- ์:
useState,useReducer์ ๊ฐ์ ํ ์ด ํ์ํ๋ค๋ฉด, Client Component๋ฅผ ์ฌ์ฉํด์ผ ํด์.
- ์:
- ์ฌ์ฉ์ ์ธํฐ๋์
(ํด๋ฆญ, ์
๋ ฅ ๋ฑ)์ด ํ์ํ๊ฐ์?
- ์:
onClick,onChange์ ๊ฐ์ ์ด๋ฒคํธ ํธ๋ค๋ฌ๊ฐ ํ์ํ๋ค๋ฉด, Client Component๋ฅผ ์ฌ์ฉํด์ผ ํด์.
- ์:
- ๋ธ๋ผ์ฐ์ ์ ์ฉ API(window, localStorage ๋ฑ)์ ์ ๊ทผํด์ผ ํ๋์?
- ์: ๋ธ๋ผ์ฐ์ API๊ฐ ํ์ํ๋ค๋ฉด, Client Component๋ฅผ ์ฌ์ฉํด์ผ ํด์.
- ๋ฒ๋ค ํฌ๊ธฐ๋ฅผ ์ต๋ํ ์ค์ด๊ณ ์ถ๋์?
- ์: ํด๋ผ์ด์ธํธ ๋ฒ๋ค์์ ์ ์ธํ๊ณ ์ถ๋ค๋ฉด, Server Component๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์์.
์ ์ฉํ ํ๊ธฐ๋ณธ์ ์ผ๋ก๋ Server Components๋ฅผ ์ฌ์ฉํ๊ณ , ์์ ์ ์๋ ์กฐ๊ฑด์ ํด๋นํ ๋๋ง Client Components๋ก ์ ํํ๋ ๊ฒ์ด ๊ฐ์ฅ ์ข์ ์ ๋ต์ด์์.
1๏ธโฃ ๋ ๋์ Next.js ๊ฐ๋ฐ์ ์ํ ์กฐ์ธ
Server Components์ Client Components๋ Next.js App Router์ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์ด์ง๋ง, ์ฌ๋ฐ๋ฅด๊ฒ ์ฌ์ฉํ์ง ์์ผ๋ฉด ์คํ๋ ค ๋ณต์ก์ฑ์ ์ฆ๊ฐ์ํค๊ฑฐ๋ ์ฑ๋ฅ์ ์ ํดํ ์ ์์ด์.
ํญ์ "์ต๋ํ Server Component๋ก ๋ง๋ค๊ณ , ๊ผญ ํ์ํ ๋ถ๋ถ๋ง Client Component๋ก ๋ถ๋ฆฌํ๋ค"๋ ์์น์ ๋ง์์์ ์๊ฒจ๋์๋ฉด ์ข์ ๊ฒ ๊ฐ์์.
๋ํ, <Suspense>์ <ErrorBoundary>๋ฅผ ์ ์ ํ ํ์ฉํ์ฌ ๋ฐ์ดํฐ ๋ก๋ฉ ์ค์ด๋ ์๋ฌ ๋ฐ์ ์ ์ฌ์ฉ์ ๊ฒฝํ์ ๊ฐ์ ํ๋ ๊ฒ๋ ์์ง ๋ง์ธ์.
์ด ๋ ๊ฐ์ง ๊ฐ๋
์ ๋ง์คํฐํ์ ๋ค๋ฉด, Next.js๋ฅผ ์ด์ฉํ ๊ณ ์ฑ๋ฅ ์น ์ ํ๋ฆฌ์ผ์ด์
๊ฐ๋ฐ์ ํ ๊ฑธ์ ๋ ๋ค๊ฐ์ค ์ ์์ ๊ฑฐ์์.
๐ฎ ์ฐธ๊ณ
- Next.js ๊ณต์ ๋ฌธ์: Server Components
- Next.js ๊ณต์ ๋ฌธ์: Client Components
- React ๊ณต์ ๋ฌธ์: Server Components
์ฐ๊ด๋ ํฌ์คํธ
- ๋จ์ด: 1,878๊ฐ21๋ถ
[๐ค] TypeScript satisfies ์ฐ์ฐ์: ํ์ ์ถ๋ก ๊ณผ ์์ ์ฑ์ ๋์์ ์ก๋ ๋น๋ฒ
TypeScript์ `satisfies` ์ฐ์ฐ์๋ฅผ ํ์ฉํ์ฌ ํ์ ์ถ๋ก ์ ์ ์ฐ์ฑ์ ์ ์งํ๋ฉด์๋ ์๊ฒฉํ ํ์ ์์ ์ฑ์ ํ๋ณดํ๋ ๋ฐฉ๋ฒ์ ์์๋ณด์ธ์. ์ค์ฉ์ ์ธ ์์๋ฅผ ํตํด ์ค์ ํ๋ก์ ํธ์ ์ ์ฉํ๋ ๋ ธํ์ฐ๋ฅผ ๊ณต์ ํฉ๋๋ค.
- ๋จ์ด: 1,207๊ฐ15๋ถ
[๐ค] React 19 ์๋ก์ด ๊ธฐ๋ฅ: use ํ , Actions, ๊ทธ๋ฆฌ๊ณ ์ปดํ์ผ๋ฌ ๋ฏธ๋ฆฌ๋ณด๊ธฐ
React 19์ ํต์ฌ ๋ณ๊ฒฝ ์ฌํญ์ธ use ํ , ์๋ฒ ์ก์ , ๊ทธ๋ฆฌ๊ณ React ์ปดํ์ผ๋ฌ์ ๋์ ๋ฐฐ๊ฒฝ๊ณผ ์ค์ ํ์ฉ ์์๋ฅผ ์ด์ค๊ธ ๊ฐ๋ฐ์ ๋๋์ด์ ๋ง์ถฐ ์์ธํ ์ค๋ช ํฉ๋๋ค. ์ต์ React ์ ๋ฐ์ดํธ๋ฅผ ํตํด ์ ํ๋ฆฌ์ผ์ด์ ์ฑ๋ฅ๊ณผ ๊ฐ๋ฐ ๊ฒฝํ์ ํฅ์์ํค๋ ๋ฐฉ๋ฒ์ ์์๋ณด์ธ์.
- ๋จ์ด: 1,512๊ฐ16๋ถ
[๐ค] Next.js App Router ์บ์ฑ ์ ๋ต: ๋ฐ์ดํฐ ์ฌ๊ฒ์ฆ (revalidatePath, revalidateTag) ์๋ฒฝ ๊ฐ์ด๋
Next.js 14 App Router์์ ํจ์จ์ ์ธ ๋ฐ์ดํฐ ์บ์ฑ ์ ๋ต๊ณผ revalidatePath, revalidateTag๋ฅผ ์ด์ฉํ ๋ฐ์ดํฐ ์ฌ๊ฒ์ฆ ๋ฐฉ๋ฒ์ ์ค๋ฌด ์์์ ํจ๊ป ์์ธํ ์์๋ณด๊ณ ์น ์ฑ๋ฅ์ ์ต์ ํํ๋ ๋ฐฉ๋ฒ์ ๋ฐฐ์๋ณด์ธ์.