๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๊ฐœ๋ฐœ/NextJS

[๊ณต์‹๋ฌธ์„œ ๋ฒˆ์—ญ] NextJS ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ

by Jaeguk 2024. 3. 21.

Client Components


ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ

ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋Š” ์„œ๋ฒ„์—์„œ ๋ฏธ๋ฆฌ ๋ Œ๋”๋ง๋œ ์ƒํ˜ธ์ž‘์šฉ์ด ๊ฐ€๋Šฅํ•œ UI๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๊ณ , ๋ธŒ๋ผ์šฐ์ €์—์„œ ๋™์ž‘ํ•˜๋Š” JavaScript๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค.
์ด ํŽ˜์ด์ง€๋Š” ์–ด๋–ป๊ฒŒ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋™์ž‘ํ•˜๋Š”์ง€, ์–ด๋–ป๊ฒŒ ๊ทธ๋“ค์ด ๋ Œ๋”๋˜๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  ์–ธ์ œ ๊ทธ๊ฒƒ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š”์ง€์— ๋Œ€ํ•ด ์•Œ์•„๋ณผ ๊ฒƒ์ด๋‹ค.

 

Benefits of Client Rendering


ํด๋ผ์ด์–ธํŠธ ๋ Œ๋”๋ง์˜ ์ด์ 

ํด๋ผ์ด์–ธํŠธ์ธก์—์„œ ๋ Œ๋”๋ง ์ž‘์—…์„ ํ•˜๋Š” ๊ฒƒ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ 2๊ฐ€์ง€ ์ด์ ์„ ๊ฐ€์ง„๋‹ค.

  • Interactivity (์ƒํ˜ธ์ž‘์šฉ): ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋Š” ์ƒํƒœ(state), ํšจ๊ณผ(effects), ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ(event listeners)๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค. ๊ทธ๊ฒƒ์€ ์œ ์ €์—๊ฒŒ ์ฆ‰๊ฐ์ ์ธ ํ”ผ๋“œ๋ฐฑ์„ ์ œ๊ณตํ•˜๊ณ , UI๋ฅผ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค.
  • Browser APIs (๋ธŒ๋ผ์šฐ์ € API): ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋Š” geolocation, localStorage์™€ ๊ฐ™์€ ๋ธŒ๋ผ์šฐ์ € API์— ๋Œ€ํ•œ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

 

Using Client Components in Next.js


NextJS์—์„œ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ ์‚ฌ์šฉํ•˜๊ธฐ

ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ "use client"๋ฅผ ํŒŒ์ผ์˜ ์ตœ์ƒ๋‹จ, ๊ทธ๋Ÿฌ๋‹ˆ๊นŒ imports ์œ„์— ์ž‘์„ฑํ•ด์•ผ ํ•œ๋‹ค.

"use client"๋Š” ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ ๋ชจ๋“ˆ ์‚ฌ์ด์˜ ๊ฒฝ๊ณ„๋ฅผ ์„ ์–ธํ•œ๋‹ค.
์ด๊ฒƒ์€ ํŒŒ์ผ์— "use client"๋ฅผ ์ •์˜ํ•จ์œผ๋กœ์จ ํ•ด๋‹น ํŒŒ์ผ ์•ˆ์—์„œ import๋œ ๋ชจ๋“  ๋ชจ๋“ˆ๊ณผ ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋“ค์€ ํด๋ผ์ด์–ธํŠธ ๋ฒˆ๋“ค์— ํฌํ•จ๋œ ๊ฒƒ์œผ๋กœ ์—ฌ๊ฒจ์ง„๋‹ค๋Š” ๋œป์ด๋‹ค.

app/counter.tsx

'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>
  )
}

 

์•„๋ž˜์˜ ๋‹ค์ด์–ด๊ทธ๋žจ์€ ๋งŒ์•ฝ "use client"๋ฅผ ์„ ์–ธํ•˜์ง€ ์•Š๊ณ  ์ค‘์ฒฉ๋œ ์ปดํฌ๋„ŒํŠธ(toogle.js)์•ˆ์—์„œ onClick๊ณผ useState๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค๋Š” ๊ฒƒ์„ ๋ณด์—ฌ์ค€๋‹ค.
App Router๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ด๋Ÿฌํ•œ API๋“ค์„ ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•˜๋Š” ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋กœ ์ƒ๊ฐํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
toggle.js์— "use client"๋ฅผ ์„ ์–ธํ•˜๋Š” ๊ฒƒ์€ ์ด๋Ÿฌํ•œ API๋“ค์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํด๋ผ์ด์–ธํŠธ ๋ฐ”์šด๋”๋ฆฌ ์•ˆ์— ๋“ค์–ด๊ฐ€๊ฒ ๋‹ค๊ณ  ๋ฆฌ์•กํŠธ์—๊ฒŒ ๋งํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

 

์—ฌ๋Ÿฌ๊ฐœ์˜ use client๋ฅผ ์—”ํŠธ๋ฆฌ ํฌ์ธํŠธ์— ์„ ์–ธํ•˜๋Š” ๊ฒƒ
๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ์˜ ์—”ํŠธ๋ฆฌ ํฌ์ธํŠธ๋“ค์— ์—ฌ๋Ÿฌ๊ฐœ์˜ 'use client'๋ฅผ ์„ ์–ธํ•  ์ˆ˜ ์žˆ๋‹ค.
์ด๊ฒƒ์€ ๋‹น์‹ ์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์—ฌ๋Ÿฌ๊ฐœ์˜ ํด๋ผ์ด์–ธํŠธ ๋ฒˆ๋“ค๋กœ ๋ถ„ํ• ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค.
๊ทธ๋Ÿฌ๋‚˜ "use client"๋Š” ํด๋ผ์ด์–ธํŠธ์ธก์—์„œ ๋ Œ๋”๋˜์–ด์•ผ ํ•˜๋Š” ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ์— ์„ ์–ธ๋  ํ•„์š”๋Š” ์—†๋‹ค.
ํ•œ๋ฒˆ ๋ฐ”์šด๋”๋ฆฌ๋ฅผ ์ •์˜ํ•˜๋ฉด, ํ•ด๋‹น ๋ฐ”์šด๋”๋ฆฌ ์•ˆ์— ์žˆ๋Š” ๋ชจ๋“  ์ž์‹ ์ปดํฌ๋„ŒํŠธ์™€ import๋œ ๋ชจ๋“ˆ๋“ค์€ ํด๋ผ์ด์–ธํŠธ ๋ฒˆ๋“ค์— ํฌํ•จ๋œ ๊ฒƒ์œผ๋กœ ์—ฌ๊ฒจ์ง„๋‹ค.

 

How are Client Components Rendered?


์–ด๋–ป๊ฒŒ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋˜์–ด ์ง€๋Š”์ง€?

NestJS์—์„œ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋Š” ์š”์ฒญ์ด ์ „์ฒด ํŽ˜์ด์ง€ ๋กœ๋“œ(์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์ฒ˜์Œ ๋ฐฉ๋ฌธํ•˜๊ฑฐ๋‚˜, ๋ธŒ๋ผ์šฐ์ € ์ƒˆ๋กœ๊ณ ์นจ์œผ๋กœ ์ธํ•œ ํŽ˜์ด์ง€ ๋ฆฌ๋กœ๋“œ)์˜ ์ผ๋ถ€์ธ์ง€ ๋˜๋Š” ์ดํ›„์˜ ํƒ์ƒ‰ ์ธ์ง€์— ๋”ฐ๋ผ ๋‹ค๋ฅด๊ฒŒ ๋ Œ๋”๋œ๋‹ค.

 

Full page load


์ดˆ๊ธฐ ํŽ˜์ด์ง€ ๋กœ๋“œ๋ฅผ ์ตœ์ ํ™”ํ•˜๊ธฐ ์œ„ํ•ด์„œ, NestJS๋Š” ํด๋ผ์ด์–ธํŠธ, ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ ๋ชจ๋‘์— ๋Œ€ํ•œ ์ •์  HTML ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ฅผ ์„œ๋ฒ„์—์„œ ๋ Œ๋”ํ•˜๊ธฐ ์œ„ํ•ด React์˜ API๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๋‹ค.
์ด๊ฒƒ์€ ์‚ฌ์šฉ์ž๊ฐ€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์ฒ˜์Œ ๋ฐฉ๋ฌธํ–ˆ์„ ๋•Œ, ๊ทธ๋“ค์ด ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ JavaScript ๋ฒˆ๋“ค์„ ๋‹ค์šด๋กœ๋“œํ•˜๊ณ , ํŒŒ์‹ฑํ•˜๊ณ , ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์„ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ณ  ํŽ˜์ด์ง€์˜ ๋‚ด์šฉ์„ ์ฆ‰๊ฐ์ ์œผ๋กœ ๋ณด๊ฒŒ๋œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

 

์„œ๋ฒ„์—์„œ๋Š”:

  1. ๋ฆฌ์•กํŠธ๋Š” ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋ฅผ React Server Component Payload(RSC Payload)๋ผ ๋ถˆ๋ฆฌ๋Š” ํŠน์ˆ˜ํ•œ ํ˜•ํƒœ์˜ ๋ฐ์ดํ„ฐ๋กœ ๋ Œ๋”ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด๊ฒƒ์€ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ์— ๋Œ€ํ•œ ์ฐธ์กฐ๋ฅผ ํฌํ•จํ•œ๋‹ค.
  2. NextJS๋Š” ์„œ๋ฒ„์—์„œ HTML์„ ๋ Œ๋”ํ•˜๊ธฐ ์œ„ํ•ด RSC Payload์™€ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ์˜ JavaScript ๋ช…๋ น์–ด๋“ค์„ ์‚ฌ์šฉํ•œ๋‹ค.

 

๊ทธ๋Ÿฐ ๋‹ค์Œ, ํด๋ผ์ด์–ธํŠธ์—์„œ๋Š”:

  1. ์„œ๋ฒ„์—์„œ ๋ Œ๋”ํ•œ HTML์€ ์ƒํ˜ธ์ž‘์šฉ์ด ๋˜์ง€ ์•Š๋Š” ์ดˆ๊ธฐ์˜ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋ฅผ ์ฆ‰๊ฐ์ ์œผ๋กœ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋œ๋‹ค.
  2. RSC Payload๋Š” ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ๋ฅผ ์กฐํ™”์‹œํ‚ค๊ณ  DOM์„ ์—…๋ฐ์ดํŠธํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋œ๋‹ค.
  3. JavaScript ๋ช…๋ น์€ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋ฅผ hydrateํ•˜์—ฌ, ์ƒํ˜ธ์ž‘์šฉ์ด ๊ฐ€๋Šฅํ•œ UI๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋œ๋‹ค.

 

hydration์ด๋ž€?
Hydration์€ ์ •์ ์ธ HTML์„ ์ƒํ˜ธ์ž‘์šฉ์ด ๊ฐ€๋Šฅํ•˜๋„๋ก DOM์— ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋ฅผ ๋ถ™์ด๋Š” ๊ณผ์ •์ด๋‹ค.
ํ™”๋ฉด ๋’ค์—์„œ, hydration์€ hydrateRoot ๋ฆฌ์•กํŠธ API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ง„ํ–‰๋œ๋‹ค.

 

Subsequent Navigations


Subsequent Navigation์—์„œ๋Š”, ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋Š” ์„œ๋ฒ„์—์„œ ๋ Œ๋”๋œ HTML ์—†์ด ์ „์ ์œผ๋กœ ํด๋ผ์ด์–ธํŠธ์ธก์—์„œ ๋ Œ๋”๊ฐ€ ์ด๋ฃจ์–ด์ง„๋‹ค.
์ด๊ฒƒ์€ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ์˜ JavaScript ๋ฒˆ๋“ค์ด ๋‹ค์šด๋กœ๋“œ๋˜๊ณ  ํŒŒ์‹ฑ๋œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.
๋ฒˆ๋“ค์ด ์ค€๋น„๋˜๋ฉด, ๋ฆฌ์•กํŠธ๋Š” ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ๋ฅผ ์กฐํ™”์‹œํ‚ค๊ณ  DOM์„ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ ์œ„ํ•ด RSC Payload๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

 

Going back to the Server Environment


์„œ๋ฒ„ ํ™˜๊ฒฝ์œผ๋กœ ๋Œ์•„๊ฐ€๊ธฐ

๋•Œ๋กœ๋Š” "use client"๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํด๋ผ์ด์–ธํŠธ ๋ฐ”์šด๋”๋ฆฌ๋ฅผ ์ •์˜ํ•œ ๋‹ค์Œ์—, ์„œ๋ฒ„ ํ™˜๊ฒฝ์œผ๋กœ ๋Œ์•„๊ฐ€๊ณ  ์‹ถ์„ ๋•Œ๋„ ์žˆ๋‹ค.
์˜ˆ๋ฅผ ๋“ค์–ด, ํด๋ผ์ด์–ธํŠธ ๋ฒˆ๋“ค์˜ ์‚ฌ์ด์ฆˆ๋ฅผ ์ค„์ด๊ณ , ์„œ๋ฒ„์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•˜๊ณ , ์„œ๋ฒ„์—์„œ๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ API๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์„ ์ˆ˜ ์žˆ๋‹ค.

์ด๋ก ์ ์œผ๋กœ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ ์•ˆ์— ์ค‘์ฒฉ๋˜์–ด ์žˆ๋”๋ผ๋„ ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ฒˆ๊ฐˆ์•„ ์‚ฌ์šฉํ•˜๊ณ , ์„œ๋ฒ„ ์•ก์…˜์„ ํ†ตํ•ด์„œ ์„œ๋ฒ„ ํ™˜๊ฒฝ์œผ๋กœ ๋Œ์•„๊ฐˆ ์ˆ˜ ์žˆ๋‹ค.
์ž์„ธํ•œ ๊ฒƒ์€ ํ•ฉ์„ฑ ํŒจํ„ด(Composition Patterns)ํŽ˜์ด์ง€๋ฅผ ์ฐธ๊ณ ํ•ด๋ผ

 


์ด๊ฑธ ์ •๋ฆฌํ•˜๋ฉด์„œ ์•Œ๊ฒŒ๋œ ๊ฒƒ์€, ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋„ ์„œ๋ฒ„์—์„œ ๋ฏธ๋ฆฌ ๋ Œ๋” ๋œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.
์ง€๊ธˆ๊นŒ์ง€๋Š” ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋Š” ์˜จ์ „ํžˆ ํด๋ผ์ด์–ธํŠธ์ธก์—์„œ ๋ Œ๋”๊ฐ€ ์ด๋ฃจ์–ด์ง€๋Š”์ง€ ์•Œ์•˜๋‹ค.

๋ฌธ๋“ ์ด์ „์— "use client"๋ฅผ ์‚ฌ์šฉํ–ˆ์Œ์—๋„ window์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋‹ค๋Š” ์—๋Ÿฌ๋ฅผ ๋ฐ›์•˜๋˜ ๊ฒƒ์ด ๊ธฐ์–ต๋‚ฌ๋‹ค.
๊ทธ๋•Œ๋Š” ์–ด์ฐŒ์ €์ฐŒ ๊ตฌ๊ธ€๋ง์„ ํ†ตํ•ด์„œ window๊ฐ€ undefined์ธ์ง€ ํ™•์ธํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ๋„ฃ์–ด์„œ ํ•ด๊ฒฐํ–ˆ์—ˆ๋Š”๋ฐ, ์„œ๋ฒ„์—์„œ ๋ Œ๋”๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ด๋Ÿฌํ•œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ฒŒ ๋˜์—ˆ๋‹ค.

 

Reference


https://nextjs.org/docs/app/building-your-application/rendering/client-components

728x90