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

RSC vs SSR

by Jaeguk 2024. 5. 4.

์„œ๋ก 


Next๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜์—ˆ์„ ๋•Œ์˜ ๋ Œ๋”๋ง ๊ณผ์ •์„ ๊ณต๋ถ€ํ•˜๋˜ ์ค‘ ์ข‹์€ ๊ธ€์„ ๋ฐœ๊ฒฌํ•ด์„œ ๊ทธ ๊ธ€์„ ๋ณด๋ฉฐ ์ •๋ฆฌํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค
=> ์›๋ณธ ๊ธ€์— ์•ฝ๊ฐ„์˜ ์‚ด๋งŒ ๋ถ™์—ฌ ์ •๋ฆฌํ•˜๋Š” ๊ฒƒ์ž„์„ ๋ฏธ๋ฆฌ ๋ฐํž™๋‹ˆ๋‹ค
(์ œ๊ฐ€ ์ฐธ๊ณ ํ–ˆ๋˜ ๊ธ€์— ๋Œ€ํ•ด์„œ๋Š” ๊ฒŒ์‹œ๋ฌผ ํ•˜๋‹จ์— ๋งํฌ๋ฅผ ๋‹ฌ์•„๋‘์—ˆ์Šต๋‹ˆ๋‹ค)

์šฐ๋ฆฌ๊ฐ€ ํ”ํžˆ React์™€ Next์˜ ๊ฐ€์žฅ ํฐ ์ฐจ์ด๋ผ๊ณ  ํ•˜๋ฉด,
CSR(Client Side Render)๊ณผ SSR(Server Side Render) ๋ผ๊ณ  ๋‹ตํ•  ๊ฒƒ์ด๋‹ค.

SSR์€ ์„œ๋ฒ„์ธก์—์„œ ์™„์„ฑ๋œ HTML์„ ๋ณด๋‚ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์— ํด๋ผ์ด์–ธํŠธ๋Š” ๊ทธ๊ฑธ ๋ฐ›์•„์„œ ๊ณง๋ฐ”๋กœ ํ™”๋ฉด์— ๋ณด์—ฌ์ฃผ๊ธฐ๋งŒ ํ•˜๋ฉด ๋˜๊ธฐ์— ์‚ฌ์šฉ์ž๊ฐ€ ๋นˆ ํ™”๋ฉด์„ ๋ณด๋Š” ์‹œ๊ฐ„์„ ์ค„์—ฌ์ค„ ์ˆ˜ ์žˆ๋‹ค.
์ด์ •๋„์˜ ๊ฐœ๋…์€ ๊ฐ€์ง€๊ณ  ์žˆ์—ˆ์ง€๋งŒ, ์กฐ๊ธˆ ๋” ์ž์„ธํ•˜๊ฒŒ ์•Œ ํ•„์š”๊ฐ€ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ๋‹ค.

 

Server Component


Next์—๋Š” Server Component์™€ Client Component์˜ ๊ฐœ๋…์ด ์กด์žฌํ•œ๋‹ค

  • Next 13๋ฒ„์ „์ด ๋“ฑ์žฅํ•˜๋ฉด์„œ ๊ต‰์žฅํžˆ ๋งŽ์€ ๋ณ€ํ™”๊ฐ€ ์žˆ์—ˆ์ง€๋งŒ, ๊ทธ ์ค‘์—์„œ ๊ฐ€์žฅ ํฐ ๋ณ€ํ™”๋Š” app router ์ด๋‹ค.
  • app router ๋ฐฉ์‹์—์„œ๋Š” ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋กœ ๋™์ž‘ํ•œ๋‹ค๋Š” ์‚ฌ์‹ค์— ์ฃผ๋ชฉํ•ด์•ผ ํ•œ๋‹ค.
  • ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด, ํŒŒ์ผ์˜ ์ตœ์ƒ๋‹จ์— 'use client' ๋ผ๊ณ  ๋ช…์‹œํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.
"use client";

import {useState} from "react";

const ClientComponent  =() => {

 const [state,setState] = useState()

 return <div>Test</div>
}

export default ClientComponent

 

RSC vs RCC


React Server Component์™€ React Client Component

์‚ฌ์‹ค ๋ฆฌ์•กํŠธ์—๋„ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ์˜ ๊ฐœ๋…์€ ์กด์žฌํ–ˆ๋‹ค

React Server Component๋Š” React 18๋ถ€ํ„ฐ ๋„์ž…๋œ ๊ฐœ๋…์œผ๋กœ, ์„œ๋ฒ„์—์„œ ๋™์ž‘ํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ง€์นญํ•œ๋‹ค.
์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์žˆ์œผ๋‹ˆ๊นŒ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋„ ์žˆ๊ฒ ์ง€?
๊ทธ๋ ‡๋‹ค. ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ์˜ ๊ฐœ๋…์ด ๋„์ž…๋˜๊ธฐ ์ „๊นŒ์ง€ ์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ–ˆ๋˜ ์ปดํฌ๋„ŒํŠธ๋Š” ๋ชจ๋‘ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ์ด๋‹ค.

์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ์™€ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ์˜ ๊ฐ€์žฅ ํฐ ์ฐจ์ด์ ์€ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง๋˜๋Š” ์žฅ์†Œ๊ฐ€ ์„œ๋ฒ„๋ƒ ํด๋ผ์ด์–ธํŠธ๋ƒ์˜ ์ฐจ์ด ๋‹ค.
์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋Š” ์„œ๋ฒ„์—์„œ ํ•œ์ฐจ๋ก€ ํ•ด์„๋œ ํ›„์— ํด๋ผ์ด์–ธํŠธ๋กœ ์ „๋‹ฌ๋˜๊ณ , ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋Š” ํด๋ผ์ด์–ธํŠธ๊ฐ€ js ๋ฒˆ๋“ค์„ ๋‹ค์šด๋กœ๋“œ ๋ฐ›์€ ํ›„์— ํ•ด์„ํ•˜๊ฒŒ ๋œ๋‹ค.

 

  • RSC์™€ RCC๋Š” ๋ Œ๋”๋ง๋˜๋Š” ์œ„์น˜๊ฐ€ ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ๊ฐ ํ•  ์ˆ˜ ์žˆ๋Š” ์—ญํ• ์ด ๊ตฌ๋ถ„๋œ๋‹ค
  • RSC๊ฐ€ ์ตœ๊ทผ์— ๋‚˜์˜จ ๊ฐœ๋…์ด๋‹ˆ๊นŒ ๋ฌด์กฐ๊ฑด RCC๋ณด๋‹ค ์ข‹๊ฒ ์ง€? ๋ผ๋Š” ์ƒ๊ฐ์€ ์ž˜๋ชป๋œ ์ƒ๊ฐ์ด๋‹ค
  • RSC์™€ RCC๋ฅผ ์ ์žฌ์ ์†Œ์— ๋ฐฐ์น˜ํ•ด์—ฌ ๊ฐœ๋ฐœํ•˜๋ ค๋Š” ์ ‘๊ทผ์ด ํ•„์ˆ˜์ ์ด๋‹ค

 

RSC์˜ ๋™์ž‘ ๋ฐฉ์‹


RSC๋Š” ์„œ๋ฒ„์—์„œ ์–ด๋–ค ์‹์œผ๋กœ ๋ Œ๋”๋ง์ด ๋˜๋Š” ๊ฒƒ์ผ๊นŒ?

RSC์™€ RCC๋ฅผ ์ ์žฌ์ ์†Œ์— ๋ฐฐ์น˜ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” RSC๊ฐ€ ์–ด๋–ค ์‹์œผ๋กœ ๋ Œ๋”๋ง๋˜๋Š”์ง€ ์ดํ•ดํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค
์•„๋ž˜์™€ ๊ฐ™์ด RSC์™€ RCC๋ฅผ ์ ์ ˆํ•˜๊ฒŒ ํ˜ผํ•ฉํ•˜์—ฌ ๊ตฌ์„ฑํ•œ ํ™”๋ฉด์ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜์ž

 

  • ๋…ธ๋ž€์ƒ‰ ๋…ธ๋“œ๋Š” ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋ฅผ, ํŒŒ๋ž€์ƒ‰ ๋…ธ๋“œ๋Š” ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์˜๋ฏธํ•œ๋‹ค
  • ์‚ฌ์šฉ์ž(๋ธŒ๋ผ์šฐ์ €)๋Š” ํ•ด๋‹น ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”ํ•˜๊ธฐ ์œ„ํ•ด์„œ ์„œ๋ฒ„๋กœ ์š”์ฒญ์„ ๋‚ ๋ฆฐ๋‹ค
  • ๊ทธ๋Ÿฌ๋ฉด ์„œ๋ฒ„๋Š” ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ๋ฅผ Root๋กœ๋ถ€ํ„ฐ ์‹คํ–‰ํ•˜๋ฉฐ ์ง๋ ฌํšŒ๋œ JSON์˜ ํ˜•ํƒœ๋กœ ์žฌ๊ตฌ์„ฑํ•˜๊ธฐ ์‹œ์ž‘ํ•œ๋‹ค

 

์ง๋ ฌํ™”?

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

 

์‰ฝ๊ฒŒ ๋งํ•ด์„œ ํŠน์ • ๊ฐœ์ฒด๋ฅผ ๋‹ค๋ฅธ ์ปดํ“จํ„ฐ ํ™˜๊ฒฝ์œผ๋กœ ์ „์†กํ•˜๊ณ  ์žฌ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ํ˜•ํƒœ๋กœ ๋ฐ”๊พธ๋Š” ๊ณผ์ •์ด๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค.
์šฐ๋ฆฌ๊ฐ€ ํ”ํžˆ ์‚ฌ์šฉํ•˜๋Š” JSON.stringify() ํ•จ์ˆ˜๊ฐ€ ์ง๋ ฌํ™”๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ํ•จ์ˆ˜์ด๋ฉฐ,
๋ฐ˜๋Œ€๋กœ JSON.parse() ํ•จ์ˆ˜๊ฐ€ ์—ญ์ง๋ ฌํ™”๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ํ•จ์ˆ˜์ด๋‹ค.

์ฃผ์˜ํ•  ์ ์€ ๋ชจ๋“  ๊ฐ์ฒด๋ฅผ ์ง๋ ฌํ™”ํ•  ์ˆ˜๋Š” ์—†๋‹ค๋Š” ๊ฒƒ ์ด๋‹ค.
๋Œ€ํ‘œ์ ์œผ๋กœ function(ํ•จ์ˆ˜)๋Š” ์ง๋ ฌํ™”๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•œ ๊ฐ์ฒด ์ด๋‹ค.

function์ด ์‹คํ–‰ ์ฝ”๋“œ์™€ ์‹คํ–‰ ์ปจํ…์ŠคํŠธ๋ฅผ ๋ชจ๋‘ ํฌํ•จํ•˜๋Š” ๊ฐœ๋…์ด๊ธฐ ๋•Œ๋ฌธ์ธ๋ฐ, ํ•จ์ˆ˜๋Š” ์ž์‹ ์ด ์„ ์–ธ๋œ ์Šค์ฝ”ํ”„์— ๋Œ€ํ•œ ์ฐธ์กฐ๋ฅผ ์œ ์ง€ํ•˜๊ณ , ๊ทธ ์‹œ์ ์˜ ์™ธ๋ถ€ ๋ณ€์ˆ˜์— ๋Œ€ํ•œ ์ฐธ์กฐ๋ฅผ ๊ธฐ์–ตํ•˜๊ณ  ์žˆ๋‹ค.
js์˜ ํด๋กœ์ €๊ฐ€ ๋ฐ”๋กœ ์ด๋Ÿฐ ํ˜„์ƒ์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ์šฉ์–ด์ด๊ธฐ๋„ ํ•˜๋‹ค.

const a = 100;

const sample = ()=>{
    console.log(a)
}

sample() //100

์ด์ฒ˜๋Ÿผ ํ•จ์ˆ˜์˜ ์‹คํ–‰ ์ปจํ…์ŠคํŠธ, ์Šค์ฝ”ํ”„, ํด๋กœ์ €๊นŒ์ง€ ๋ชจ๋‘ ์ง๋ ฌํ™”ํ•  ์ˆ˜๋Š” ์—†๊ธฐ ๋•Œ๋ฌธ์— function์€ ์ง๋ ฌํ™”๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•œ ๊ฐ์ฒด๋กœ ๋ถ„๋ฅ˜๋˜๋Š” ๊ฒƒ์ด๋‹ค

์ง๋ ฌํ™” ๊ณผ์ •์€ ๋ชจ๋“  ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‹คํ–‰ํ•ด์„œ JSON ๊ฐ์ฒด ํ˜•ํƒœ์˜ ํŠธ๋ฆฌ๋กœ ์žฌ๊ตฌ์„ฑํ•  ๋•Œ๊นŒ์ง€ ์ง„ํ–‰๋œ๋‹ค.
์˜ˆ๋ฅผ ๋“ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

<div style={{backgroundColor:'green'}}>hello world</div> //JSX ์ฝ”๋“œ๋Š” createElement์˜ syntax sugar๋‹ค.

> React.createElement(div,{style:{backgroundColor:'green'}},"hello world")

> {
  $$typeof: Symbol(react.element),
  type: "div",
  props: { style:{backgroundColor:"green"}, children:"hello world" },
  ...
} //์ด๋Ÿฐ ํ˜•ํƒœ๋กœ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ˆœ์ฐจ์ ์œผ๋กœ ์‹คํ–‰ํ•œ๋‹ค.
  • ๋‹ค๋งŒ ์ด ๊ณผ์ •์„ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ์— ๋Œ€ํ•ด ์ง„ํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ RCC์ผ ๊ฒฝ์šฐ์—๋Š” ๊ฑด๋„ˆ๋›ฐ๊ฒŒ ๋œ๋‹ค
    • RCC์˜ ๋ Œ๋”๋ง์€ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋„˜๊ธฐ๋Š” ๊ฒƒ์ด๋‹ค
  • ํ•˜์ง€๋งŒ RCC๋ฅผ ์„œ๋ฒ„์—์„œ ํ•ด์„ํ•˜์ง€ ์•Š๊ณ  ๊ฑด๋„ˆ ๋›ด๋‹ค๊ณ  ํ•ด์„œ ๋น„์›Œ๋‘”๋‹ค๋ฉด ์‹ค์ œ ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ์™€์˜ ๊ดด๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค
  • ๋”ฐ๋ผ์„œ RCC์˜ ๊ฒฝ์šฐ ์ง์ ‘ ํ•ด์„ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, "์ด๊ณณ์€ RCC๊ฐ€ ๋ Œ๋”๋ง๋˜๋Š” ์œ„์น˜์ž…๋‹ˆ๋‹ค" ๋ผ๋Š” placeholder๋ฅผ ๋Œ€์‹  ๋ฐฐ์น˜ํ•˜๊ฒŒ ๋œ๋‹ค

 

{
  $$typeof: Symbol(react.element),
  type: {
    $$typeof: Symbol(react.module.reference),
    name: "default", //export default๋ฅผ ์˜๋ฏธ
    filename: "./src/ClientComponent.js" //ํŒŒ์ผ ๊ฒฝ๋กœ
  },
  props: { children: "some children" },
}

RCC๋Š” ๊ณง ํ•จ์ˆ˜์ด๊ธฐ ๋•Œ๋ฌธ์—, ์ง๋ ฌํ™”๋ฅผ ํ•  ์ˆ˜ ์—†๋‹ค
๋”ฐ๋ผ์„œ ํ•จ์ˆ˜๋ฅผ ์ง์ ‘ ์ฐธ์กฐํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, module reference ๋ผ๋Š” ์ƒˆ๋กœ์šด ํƒ€์ž…์„ ์ ์šฉํ•˜๊ณ , ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ์˜ ๊ฒฝ๋กœ๋ฅผ ๋ช…์‹œํ•จ์œผ๋กœ์จ ์ง๋ ฌํ™”๋ฅผ ๋Œ€์‹ ํ•˜๊ณ  ์žˆ๋‹ค


์ด๋Ÿฌํ•œ ์ง๋ ฌํ™” ์ž‘์—…์„ ๋งˆ์นœ ํ›„ ์ƒ์„ฑ๋œ JSON Tree๋ฅผ ๋„์‹ํ™”ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ˜•ํƒœ์ด๋‹ค

  • ์ด๋ ‡๊ฒŒ ๋„์ถœ๋œ ๊ฒฐ๊ณผ๋ฌผ์„ Stream ํ˜•ํƒœ๋กœ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ „๋‹ฌ์„ ๋ฐ›๊ฒŒ ๋œ๋‹ค.
  • ํ•จ๊ป˜ ๋‹ค์šด๋กœ๋“œํ•œ js bundle์„ ์ฐธ์กฐํ•˜์—ฌ module reference ํƒ€์ž…์ด ๋“ฑ์žฅํ•  ๋•Œ๋งˆ๋‹ค RCC๋ฅผ ๋ Œ๋”๋งํ•ด์„œ ๋นˆ ๊ณต๊ฐ„์„ ์ฑ„์›Œ๋†“๋Š”๋‹ค.
  • ๊ทธ๋Ÿฐ ๋‹ค์Œ DOM์— ๋ฐ˜์˜ํ•˜๋ฉด ์‹ค์ œ ํ™”๋ฉด์— ์Šคํฌ๋ฆฐ์ด ๋ณด์—ฌ์ง€๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

 

  • placeholder๋กœ ํ‘œ์‹œ๋˜์–ด ์žˆ๋˜ ๋…ธ๋“œ๋“ค์ด ์‹ค์ œ ์ปดํฌ๋„ŒํŠธ๋กœ ๋Œ€์ฒด๊ฐ€ ๋˜์–ด ํ™”๋ฉด์— ๋ณด์—ฌ์ง€๊ฒŒ ๋œ๋‹ค

 

RSC์˜ ์ œ์•ฝ์‚ฌํ•ญ


์šฐ๋ฆฌ๋Š” RSC, RCC๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ๋–„ ๋ช‡๊ฐ€์ง€ ์ œ์•ฝ์‚ฌํ•ญ์„ ๋„์ถœํ•ด๋‚ผ ์ˆ˜ ์žˆ๋‹ค

 

  1. RSC์—์„œ RCC๋กœ function๊ณผ ๊ฐ™์ด ์ง๋ ฌํ™”๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•œ ๊ฐ์ฒด๋ฅผ props๋กœ ๋„˜๊ฒจ์ค„ ์ˆ˜ ์—†๋‹ค
{
   $$typeof: Symbol(react.element),
   type: "div",
   props: { 
         children: {
           $$typeof: Symbol(react.element),
           type: {
             $$typeof: Symbol(react.module.reference),
             name: "default",
             filename: "./src/ClientComponent.js"
           },
           props: {callback:function}, // ์ด์ฒ˜๋Ÿผ JSON์— function์ด ๋ช…์‹œ๋˜์–ด์•ผ๋งŒ ํ•œ๋‹ค.
           ...
         }
     },
   ...
 }
  • RSC๋Š” ์„œ๋ฒ„์—์„œ ํ•ด์„๋˜์–ด ์ง๋ ฌํ™”๋œ JSON ํ˜•ํƒœ๋กœ ๋ณ€ํ™˜๋œ๋‹ค๊ณ  ํ–ˆ๋‹ค
  • ๋•Œ๋ฌธ์— ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์„ค๋ช…ํ•˜๋Š” ๋ชจ๋“  ์š”์†Œ๋Š” ์ง๋ ฌํ™”๊ฐ€ ๊ฐ€๋Šฅํ•ด์•ผ ํ•œ๋‹ค๋Š” ์ „์ œ์กฐ๊ฑด์ด ๋ถ‡๋Š”๋‹ค
  • ๋งŒ์•ฝ RSC๊ฐ€ Child์—๊ฒŒ function์„ props๋กœ ๋„˜๊ฒจ์ฃผ๊ฒŒ ๋˜๋ฉด, JSON์— ์ด ์‚ฌ์‹ค์ด ๋ช…์‹œ๋˜์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค

 

ํ•˜์ง€๋งŒ RSC์—์„œ ๋‹ค๋ฅธ RSC๋กœ function์„ ๋„˜๊ฒจ์ฃผ๋Š” ๊ฒƒ์—๋Š” ๋ฌธ์ œ๊ฐ€ ์—†์ด ๊ฐ€๋Šฅํ•˜๋‹ค
์„œ๋ฒ„์—์„œ ๋ Œ๋”๋ง๋˜๋Š” RSC๊ฐ„์˜ ํ•จ์ˆ˜ ์ „๋‹ฌ์„ ๊ตณ์ด client๋ฅผ ๋„˜๊ธฐ๋Š” Stream์— ์„œ์ˆ ํ•  ํ•„์š”๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ƒ๋žตํ•˜๊ฑฐ๋‚˜ placeholder๋กœ ๋Œ€์ฒดํ•œ ๊ฒŒ ์•„๋‹๊นŒ๋ผ๊ณ  ๊ธ€์˜ ์ž‘์ž๋Š” ์˜ˆ์ธกํ•˜๊ณ  ์žˆ๋‹ค

๋˜ํ•œ, next์˜ server action์„ ์‚ฌ์šฉํ•˜๋ฉด, RSC์—์„œ RCC๋กœ ํ•จ์ˆ˜๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜๋„ ์žˆ๋Š”๋ฐ, ์•„๋ž˜์™€ ๊ฐ™์ด RSC์—์„œ 'use server directive์™€ ํ•จ๊ป˜ ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•˜๋ฉด RCC๋กœ ๋„˜๊ฒจ์ค„ ์ˆ˜ ์žˆ๋‹ค

const ServerComponent = ()=>{
  const add = async (a:number,b:number) =>{
    'use server'
    return a+b
  }

  return <div>
        <ClientComponent addFunc={add}/>
    </div>
}
  • ๋‹ค๋งŒ ํ•ด๋‹น function์˜ params์™€ return์€ ๋ชจ๋‘ ์ง๋ ฌํ™”๊ฐ€ ๊ฐ€๋Šฅํ•ด์•ผ ํ•œ๋‹ค๋Š” ์กฐ๊ฑด์ด ๋ถ™๋Š”๋‹ค
  • server action์œผ๋กœ ์„ ์–ธํ•œ ํ•จ์ˆ˜๋ฅผ RSC์—์„œ RCC๋กœ ๋„˜๊ฒจ์ค„ ๋•Œ๋Š” function ์ž์ฒด๋ฅผ ๋„˜๊ฒจ์ค€๋‹ค๊ธฐ ๋ณด๋‹ค๋Š”, api์˜ ๋ช…์„ธ๋ฅผ ๋„˜๊ฒจ์ฃผ๊ณ , ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ๊ทธ๋•Œ ์„œ๋ฒ„์— api๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ๊ฒฐ๊ณผ๊ฐ’์„ ๋ฐ›์•„์˜ค๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋™์ž‘ํ•˜์—ฌ ์ œ์•ฝ์‚ฌํ•ญ์„ ์šฐํšŒํ•˜๋Š” ๊ฒƒ์ด๋ผ ์˜ˆ์ƒํ•œ๋‹ค
  • ์ž์„ธํ•œ ๋‚ด์šฉ์€ Next ๊ณต์‹๋ฌธ์„œ์˜ server action ๋ถ€๋ถ„์„ ์ฐธ์กฐํ•˜๋ฉด ์ข‹์„ ๊ฒƒ์ด๋‹ค

 

  1. RCC๋Š” RSC๋ฅผ ์ง์ ‘ return ํ•ด์ค„ ์ˆ˜ ์—†์œผ๋ฉฐ, ๋ฐ˜๋“œ์‹œ children prop์˜ ํ˜•ํƒœ๋กœ ๋„˜๊ฒจ์ฃผ์–ด์•ผ ํ•œ๋‹ค
  • ์š”์ฒญ์ด ๋“ค์–ด์˜ค๋ฉด ์„œ๋ฒ„์—์„œ ๋ชจ๋“  RSC๊ฐ€ ์ˆœ์ฐจ์ ์œผ๋กœ ์‹คํ–‰๋˜๋ฉฐ, ์ค‘๊ฐ„์— RCC๋ฅผ ๋งŒ๋‚˜๋ฉด placeholder๋กœ ํ‘œ์‹œํ•ด๋‘๊ณ  ๋„˜์–ด๊ฐ„๋‹ค๊ณ  ํ–ˆ๋‹ค
  • ์ฆ‰, RCC๋Š” ์‹คํ–‰์ด ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— RCC ๋‚ด๋ถ€์—์„œ ๋ฐ˜ํ™˜๋˜๋Š” RSC ๋˜ํ•œ ์„œ๋ฒ„ ํด๋ผ์ด์–ธํŠธ์ž„์—๋„ ์„œ๋ฒ„์—์„œ ์‹คํ–‰๋˜์ง€ ๋ชปํ•œ๋‹ค
  • ์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ ํ•ด๋‹น RSC๋Š” RCC์™€ ๋™์ผํ•˜๊ฒŒ ํด๋ผ์ด์–ธํŠธ์—์„œ ๋™์ž‘ํ•˜๊ฒŒ ๋œ๋‹ค
  • ํ•˜์ง€๋งŒ children prop์„ ํ†ตํ•ด์„œ RSC๋ฅผ ๋„˜๊ธฐ๊ฒŒ ๋˜๋ฉด, ์‚ฌ์‹ค์ƒ ๊ณตํ†ต ๋ถ€๋ชจ๊ฐ€ ๋ Œ๋”๋ง๋˜๋Š” ์‹œ์ ์— RSC๊ฐ€ ์‹คํ–‰์ด ๋˜๊ณ , ๊ทธ ๊ฒฐ๊ณผ๊ฐ’์„ children์œผ๋กœ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค
function ParentClientComponent({children}) {
    ...
  return <div onChange={...}>{children}</div>;
}

function ChildServerComponent() {
    ...
  return <div>server component</div>;
}

function ContainerServerComponent() {
  return <ParentClientComponent>
            <ChildServerComponent/>
    </ParentClientComponent>;
}
  • ์œ„์™€ ๊ฐ™์ด ChildServerComponent๋Š” ParentClientComponent์˜ ์ž์‹ ์ปดํฌ๋„ŒํŠธ์ด๋‹ค
  • ํ•˜์ง€๋งŒ ์‚ฌ์‹ค์ƒ ContainerServerComponent๋ฅผ ๊ณตํ†ต ๋ถ€๋ชจ๋กœ ๊ฐ–๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ContainerServerComponent๊ฐ€ ๋ Œ๋”๋ง๋˜๋Š” ์‹œ์ ์— ChildServerComponent๋„ ํ•จ๊ป˜ ๋ Œ๋”๋ง๋˜์–ด ๊ทธ ๊ฒฐ๊ณผ๊ฐ’์ดParentChildComponent์— ๋„˜๊ฒจ์ง€๊ณ  ์žˆ๋‹ค

 

{
  // The ClientComponent element placeholder with "module reference"
  $$typeof: Symbol(react.element),
  type: {
    $$typeof: Symbol(react.module.reference),
    name: "default",
    filename: "./src/ParentClientComponent.js"
  },
  props: {
    children: {
      $$typeof: Symbol(react.element),
      type: "div",
      props: {
        children: "server component"
      }
    }
  }
}

 

RSC vs SSR


๋‚˜๋Š” ์ด ๊ธ€์„ ์ฝ์œผ๋ฉด์„œ RSC์™€ SSR์ด ๋‹ค๋ฅธ ๊ฐœ๋…์ด๋ผ๋Š” ๊ฒƒ์„ ์•Œ๊ฒŒ ๋˜์—ˆ๋‹ค

์ง€๊ธˆ๊นŒ์ง€ ๊ธ€์„ ์ฝ์€ ์šฐ๋ฆฌ๋Š” ์ด๋Ÿฌํ•œ ์ƒ๊ฐ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค

์ปดํฌ๋„ŒํŠธ๊ฐ€ ์„œ๋ฒ„์—์„œ ํ•ด์„๋ผ์„œ ํด๋ผ์ด์–ธํŠธ๋กœ ์ „๋‹ฌ๋˜๋Š” ๊ฒŒ SSR ์•„๋‹ˆ์•ผ?

์‹ค์ œ๋กœ RSC์™€ SSR์€ ์„œ๋ฒ„์—์„œ ์ฒ˜๋ฆฌํ•œ๋‹ค๋Š” ๊ณตํ†ต์  ์™ธ์—๋Š” ํ•ด๊ฒฐํ•˜๊ณ ์ž ํ•˜๋Š” ๋ชฉํ‘œ๋„ ๋‹ค๋ฅด๊ณ , ์ผ์–ด๋‚˜๋Š” ์‹œ์ ๊ณผ ์ตœ์ข… ์‚ฐ์ถœ๋ฌผ๋„ ๋‹ค๋ฅธ ์™„์ „ํžˆ ๋ณ„๊ฐœ์˜ ๊ฐœ๋… ์ด๋ผ๊ณ  ํ•œ๋‹ค
๋”ฐ๋ผ์„œ ๋ฐ˜๋“œ์‹œ ๋‘˜ ์ค‘ ํ•˜๋‚˜๋ฅผ ์„ ํƒํ•  ํ•„์š”๋„ ์—†๊ณ , ํ•„์š”์— ๋”ฐ๋ผ RSC์™€ SSR์„ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋ฉด ํฐ ์‹œ๋„ˆ์ง€๋ฅผ ๋‚ผ ์ˆ˜๋„ ์žˆ๋‹ค

์šฐ๋ฆฌ๊ฐ€ ์ž‘์„ฑํ•œ ์†Œ์Šค์ฝ”๋“œ๊ฐ€ ๋ธŒ๋ผ์šฐ์ €์— ๋ณด์—ฌ์ง€๊ธฐ ์œ„ํ•ด์„œ๋Š” ์šฐ์„  ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์‹คํ–‰๋˜์–ด ๋ฐ์ดํ„ฐ๊ฐ€ ํ•ด์„๋˜์–ด์•ผ ํ•˜๊ณ ,
ํ•ด์„๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ๋‹ค์‹œ HTML๋กœ ๋ณ€ํ™˜๋˜๋Š” ๊ณผ์ •์„ ๊ฑฐ์ ธ์•ผ ํ•œ๋‹ค

RSC๋Š” ์ด ์ค‘ ์ „์ž(ํ•ด์„)์— ํ•ด๋‹นํ•˜๋Š” ๋‹จ๊ณ„์— ๊ด€์—ฌํ•˜๊ณ , SSR์€ ํ›„์ž(HTML๋กœ ๋ณ€ํ™˜)์— ๊ด€์—ฌํ•œ๋‹ค

๊ทธ๋ ‡๋‹ค๋ฉด, ๋˜ ์ด๋Ÿฌํ•œ ์ƒ๊ฐ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค

RSC๋ฅผ ์“ฐ๋“ , RCC๋ฅผ ์“ฐ๋“  SSR์„ ์‚ฌ์šฉํ•˜๋ฉด ์–ด์งœํ”ผ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ฐ›๊ฒŒ ๋˜๋Š” ์ตœ์ข… ์‚ฐ์ถœ๋ฌผ์€ HTML๋กœ ๋™์ผํ•œ ๊ฒƒ ์•„๋‹Œ๊ฐ€?
๊ทธ๋ ‡๋‹ค๋ฉด RSC์™€ SSR์„ ํ•จ๊ป˜ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ์˜ ์ด์ ์€ ๋ฌด์—‡์ธ๊ฐ€?

 

Next์˜ SSR


Next์—์„œ๋Š” SSR์„ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์„๊นŒ?

์ด๊ฑธ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด์„œ CSR๊ณผ SSR์˜ ๊ฐœ๋…์— ๋Œ€ํ•ด์„œ ๋จผ์ € ์ •๋ฆฌ๋ฅผ ํ•ด๋ณด์ž

 

CSR vs SSR


CSR๊ณผ SSR์˜ ์ฐจ์ด

  • Client Side Rendering(CSR)์€ ๋ง ๊ทธ๋Œ€๋กœ ํด๋ผ์ด์–ธํŠธ์—์„œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค
  • ์„œ๋ฒ„์—์„œ ๋นˆ HTML๊ณผ js bundle์„ ๋‹ค์šด๋ฐ›๊ณ , ์ด js ์†Œ์Šค ์ฝ”๋“œ๋ฅผ ํด๋ผ์ด์–ธํŠธ์—์„œ ํ•ด์„ํ•ด์„œ ์ฒ˜์Œ๋ถ€ํ„ฐ ๊ทธ๋ ค๋‚˜๊ฐ€๊ฒŒ ๋œ๋‹ค
  • ๋•Œ๋ฌธ์— ์ดˆ๊ธฐ ๋กœ๋”ฉ ์†๋„๊ฐ€ ๋Š๋ฆฌ์ง€๋งŒ, ์Šคํฌ๋ฆฐ๊ฐ„ ์ด๋™์ด๋‚˜ ์ธํ„ฐ๋ž™์…˜์— ๊ฐ•์ ์ด ์žˆ๋‹ค
    • ๋นˆ HTML์„ ๋ฐ›์•„์™€์„œ, js๋ฅผ ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ ์‹คํ–‰์‹œ์ผœ์„œ ์Šคํฌ๋ฆฐ์„ ๊ตฌ์„ฑํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์†๋„๊ฐ€ ๋Š๋ฆฌ๋‹ค

 

  • Server Side Rendering(SSR)์€ ์„œ๋ฒ„์—์„œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ•ด์„ํ•ด์„œ ์ตœ์ข… ๊ฒฐ๊ณผ๋ฌผ์ธ HTML ํŒŒ์ผ์„ ๋‚ด๋ ค์ฃผ๋Š” ๊ฒƒ ์„ ์˜๋ฏธํ•œ๋‹ค
  • CSR๊ณผ๋Š” ๋ฐ˜๋Œ€๋กœ ์ดˆ๊ธฐ ๋กœ๋”ฉ ์†๋„๊ฐ€ ๋น ๋ฅด์ง€๋งŒ, ํŽ˜์ด์ง€๋ฅผ ์ด๋™ํ•  ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ์šด HTML์„ ์š”์ฒญํ•ด์„œ ๋ฐ›๋Š” ์‹œ๊ฐ„์ด ํ•„์š”ํ•˜๊ณ , ํ˜„์žฌ ํ™”๋ฉด์—์„œ๋„ ์ž‘์€ ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ๋ฐœ์ƒํ•˜๋ฉด ์ฒ˜์Œ๋ถ€ํ„ฐ HTML์„ ๋กœ๋“œํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์Šคํฌ๋ฆฐ๊ฐ„ ์ด๋™์ด๋‚˜ ์ธํ„ฐ๋ž™์…˜์— ์•ฝ์ ์ด ์žˆ๋‹ค
    • ์ด๋ฏธ ์™„์„ฑ๋œ HTML์„ ๋‚ด๋ ค์คฌ๊ธฐ ๋•Œ๋ฌธ์—, ์‚ฌ์šฉ์ž์™€์˜ ์ธํ„ฐ๋ž™์…˜์„ ํ•˜๊ฒŒ ๋˜๋ฉด ์‚ฌ์šฉ์ž์˜ ์ž…๋ ฅ์— ๋”ฐ๋ผ ์ƒˆ๋กญ๊ฒŒ ๋˜๋‹ค์‹œ HTML์„ ๋ฐ›์•„์™€์•ผ ํ•œ๋‹ค
    • ๋ฆฌ์•กํŠธ๋Š” SPA(Single Page Application)์ด๊ธฐ ๋•Œ๋ฌธ์— ํŽ˜์ด์ง€ ์ด๋™์„ ํ•˜๊ฒŒ ๋˜๋ฉด ๊ต‰์žฅํžˆ ์Šค๋ฌด์Šค ํ•˜์ง€๋งŒ, Next์—์„œ๋Š” ํŽ˜์ด์ง€ ์ด๋™์„ ํ•˜๊ฒŒ ๋˜๋ฉด ์‹œ๊ฐ„์ด ์˜ค๋ž˜๊ฑธ๋ฆฌ๊ณ  ๊นœ๋นก์ž„์ด ๋ฐœ์ƒํ•œ๋‹ค
  • ์‚ฌ์‹ค Next์—์„œ ์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” SSR์€ ์ „ํ†ต์ ์ธ ์˜๋ฏธ์˜ SSR์€ ์•„๋‹ˆ๋‹ค
  • SSR๊ณผ CSR์˜ ์žฅ์ ๋งŒ์„ ์ทจํ•˜๊ธฐ ์œ„ํ•ด์„œ ์ผ์ข…์˜ ์ ˆ์ถฉ์ ์„ ์ฐพ์€ ํ˜•ํƒœ๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค
  • ์ดˆ๊ธฐ ๋กœ๋”ฉ ์†๋„๊ฐ€ ๋Š๋ฆฌ๋‹ค๋Š” CSR์˜ ๋‹จ์ ์„ ๋ณด์™„ํ•˜๊ธฐ ์œ„ํ•ด์„œ ์ดˆ๊ธฐ ๋กœ๋”ฉ์‹œ์—๋Š” HTML ํŒŒ์ผ์„ SSR์„ ํ†ตํ•ด ๋น ๋ฅด๊ฒŒ ๋ฐ›์•„์˜ค๊ณ , ์ด์™€ ๋ณ‘๋ ฌ์ ์œผ๋กœ js ๋ฒˆ๋“ค๋„ ํ•จ๊ป˜ ๋ฐ›์•„์™€์„œ ๋ฏธ๋ฆฌ ๋ฐ›์•„์˜จ HTML๊ณผ ๋ณ‘ํ•ฉํ•˜๋Š” Hydration ๊ณผ์ •์„ ๊ฑฐ์น˜๋Š” ๊ฒƒ์ด๋‹ค
  • ๊ทธ ๊ฒฐ๊ณผ ๋น ๋ฅธ ๋กœ๋”ฉ์— ๊ฐ•์ ์ด ์žˆ๋Š” SSR๊ณผ ์ธํ„ฐ๋ž™์…˜์— ๊ฐ•์ ์ด ์žˆ๋Š” CSR์˜ ์žฅ์ ์„ ๋ชจ๋‘ ์ทจํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค
  • ์ฆ‰, Next์˜ SSR ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ CSR์˜ ํŠน์ง•๋„ ๋งŽ์ด ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฏ€๋กœ RSC๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ, ๊ทธ ์ด์ ์ด ๋”์šฑ ํฌ๊ฒŒ ๊ทน๋Œ€ํ™” ๋  ์ˆ˜ ์žˆ๋‹ค

 

SSR + RSC ์˜ˆ์‹œ


Next๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋งŒ๋“ค์–ด์ง„ ๊ฒƒ์œผ๋กœ ์•Œ๋ ค์ง„ ๋„ทํ”Œ๋ฆญ์Šค ํŽ˜์ด์ง€๋ฅผ ์˜ˆ์‹œ๋กœ ๋ณด์ž

  • ๋„ทํ”Œ๋ฆญ์Šค ํŽ˜์ด์ง€์— ์ฒ˜์Œ ๋กœ๋”ฉํ•˜๊ฒŒ ๋˜๋ฉด, ์„œ๋ฒ„์—์„œ ์ด๋ฏธ ์–ด๋Š์ •๋„ ์™„์„ฑ๋œ HTML์„ ๋ฐ›์•„์˜ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค
  • ์œ„์˜ ์˜ˆ์‹œ๋Š” ๋”์šฑ ํ™•์‹คํžˆ ํ•˜๊ธฐ ์œ„ํ•ด์„œ JS๋ฅผ Disabled ์‹œํ‚ค๊ณ  ์š”์ฒญ์„ ๋ณด๋‚ธ ๊ฒƒ์ด๋‹ค

 

  • React๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค๊ณ  ์•Œ๋ ค์ง„ ํ˜„์žฌ ๋‚ด๊ฐ€ ๊ธ€์„ ์ž‘์„ฑํ•˜๊ณ  ์žˆ๋Š” ํ‹ฐ์Šคํ† ๋ฆฌ์˜ ํ™ˆํŽ˜์ด์ง€
  • ํ‹ฐ์Šคํ† ๋ฆฌ ํŽ˜์ด์ง€์—์„œ JS๋ฅผ Disabled ์‹œ์ผœ๋ฒ„๋ฆฌ๋ฉด ์ด์ฒ˜๋Ÿผ ๋นˆ ํ™”๋ฉด๋งŒ ๋ณด๊ฒŒ ๋œ๋‹ค
    • ๊ธฐ๋ณธ์ ์ธ ๋ถ€๋ถ„(header, meta, ...)๋งŒ ์ฑ„์›Œ์ ธ ์žˆ๋‹ค
  • CSR์—์„œ๋Š” ๋นˆ HTML์„ ๋ณด๋‚ด์ค€ ๋‹ค์Œ js ๋ฒˆ๋“ค์„ ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ ํ•ด์„ํ•ด์„œ ํ™”๋ฉด์„ ๊ตฌ์„ฑํ•œ๋‹ค๊ณ  ํ–ˆ๋Š”๋ฐ, js๋ฅผ ๋ง‰์•„๋ฒ„๋ฆฌ๋‹ˆ ์ด์™€ ๊ฐ™์ด ๋นˆ ํ™”๋ฉด๋งŒ ๋ณด๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด๋‹ค

 

RSC์˜ ์žฅ์ 


RSC๊ฐ€ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€ ๋ชจ๋‘ ์ดํ•ดํ–ˆ์œผ๋‹ˆ, RSC์˜ ์žฅ์ ์„ ์‰ฝ๊ฒŒ ๋‚ฉ๋“ํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค

 

Zero Bundle Size


์„œ๋ฒ„ ์ธก์—์„œ ๋ฏธ๋ฆฌ ๋ชจ๋‘ ํ•ด์„์„ ํ•ด์„œ ์ง๋ ฌํ™”๋œ JSON ํ˜•ํƒœ๋กœ ์ „๋‹ฌํ•˜๊ธฐ ๋–„๋ฌธ์— ์–ด๋– ํ•œ Bundle๋„ ํ•„์š”ํ•˜์ง€ ์•Š๋‹ค

RSC์˜ ์†Œ์Šค ํŒŒ์ผ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, RSC์—์„œ๋งŒ ์‚ฌ์šฉํ•˜๋Š” ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ๊ฒฝ์šฐ์—๋„ ๋ฒˆ๋“ค์— ํฌํ•จ๋  ํ•„์š”๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋ฒˆ๋“ค ์‚ฌ์ด์ฆˆ๋ฅผ ํš๊ธฐ์ ์œผ๋กœ ๊ฐ๋Ÿ‰ํ•  ์ˆ˜ ์žˆ๋‹ค

์ด๋Ÿฌํ•œ ๋ถ€๋ถ„์€ Next์˜ TTI(Time To Interactive) ๊ฐœ์„ ์—๋„ ํฌ๊ฒŒ ๊ธฐ์—ฌํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ด์ „์— ์‚ดํŽด๋ดค๋“ฏ์ด Next์—์„œ SSR์„ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ํ•˜๋”๋ผ๋„ ์ดˆ๊ธฐ ๋กœ๋”ฉ์†๋„์— ์ด์ ์ด ์žˆ์„ ๋ฟ CSR๊ณผ ๋™์ผํ•œ ์‚ฌ์ด์ฆˆ์˜ js ๋ฒˆ๋“ค์„ ๋‹ค์šด๋ฐ›์•„์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— TTI๋Š” ์—ฌ์ „ํžˆ CSR ๋Œ€๋น„ ํฐ ๋ฉ”๋ฆฌํŠธ๊ฐ€ ์—†์—ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค

ํ•˜์ง€๋งŒ RSC๋ฅผ ๋„์ž…ํ•˜๋ฉด ๋‹ค์šด๋ฐ›์•„์•ผ ํ•˜๋Š” ๋ฒˆ๋“ค ์‚ฌ์ด์ฆˆ๊ฐ€ ์ค„์–ด๋“ค๊ฒŒ ๋˜๋ฏ€๋กœ, TTI ๊ฐœ์„ ์— ๊ธฐ์—ฌํ•  ์ˆ˜ ์žˆ๋‹ค

 

No More getServerSideProps / getStaticProps


Next 13 ๋ฒ„์ „์œผ๋กœ ๋ณ€๊ฒฝ๋˜๋ฉด์„œ ๋”์ด์ƒ getServerProps / getStaticProps๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•˜์ง€ ์•Š๊ฒŒ ๋˜์—ˆ๋‹ค

์‚ฌ์‹ค ๋‚˜๋Š” Next 12 ๋ฒ„์ „์„ ์‚ฌ์šฉํ•ด๋ณธ ์ ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ํ”ผ๋ถ€๋กœ ์™€๋‹ฟ์ง€๋Š” ์•Š์ง€๋งŒ, ์ด์ „์ด ํ›จ์”ฌ ๋ถˆํŽธํ–ˆ์„ ๊ฒƒ์ด๋ž€ ๊ฑด ์˜ˆ์ƒํ•ด๋ณผ ์ˆ˜ ์žˆ์—ˆ๋‹ค
๊ธฐ์กด์—๋Š” Data fetch ๋“ฑ์„ ์ˆ˜ํ–‰ํ•  ๋•Œ๋Š” ๋ฐ˜๋“œ์‹œ getServerSideProps ๋˜๋Š” getStaticProps ํ•จ์ˆ˜๋ฅผ page ์ตœ์ƒ๋‹จ์—์„œ ์ˆ˜ํ–‰ํ•˜๊ณ , ์ด๋ฅผ page์— props๋กœ ๋„˜๊ฒจ์„œ ์‚ฌ์šฉํ•ด์•ผ ํ–ˆ๋‹ค

์ด ๊ณผ์ •์€ ์ˆœ์ˆ˜ React์™€๋Š” ๊ดด๋ฆฌ๊ฐ€ ์žˆ์–ด์„œ ์ฒ˜์Œ Next๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ๋‚ฏ์„ค ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, ๋ฌด์กฐ๊ฑด ์ตœ์ƒ๋‹จ์—์„œ fetchํ•œ ํ›„์— page์— props๋กœ ๋„˜๊ฒจ์ค„ ์ˆ˜ ๋ฐ–์— ์—†๋Š” ๊ตฌ์กฐ ๋•Œ๋ฌธ์— data๋ฅผ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ์‚ฌ์šฉํ•˜๋ ค๋ฉด props drilling์ด ๋ถˆ๊ฐ€ํ”ผํ–ˆ๋‹ค.

๋ฐ˜๋ฉด RSC๋Š” ๊ทธ ์ž์ฒด๊ฐ€ ์„œ๋ฒ„์—์„œ ๋ Œ๋”๋ง๋˜๊ธฐ ๋•Œ๋ฌธ์—, ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์—์„œ Data Fetch๋ฅผ ์‹œ๋„ํ•ด๋„ ๊ดœ์ฐฎ๋‹ค
์ฆ‰, data๊ฐ€ ํ•„์š”ํ•œ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ง์ ‘ data fetch๊ฐ€ ๊ฐ€๋Šฅํ•ด์กŒ๊ณ , Next 13์˜ app router์—์„œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๊ฐ€ RSC์ด๊ธฐ ๋•Œ๋ฌธ์—, ๋” ์ด์ƒ getServerSideProps ๋˜๋Š” getStaticProps๋Š” ๋ถˆํ•„์š”ํ•œ ํ•จ์ˆ˜๊ฐ€ ๋˜์—ˆ๋‹ค

 

Automatic Code Splitting


์›๋ž˜๋Š” Code Splitting์„ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” React.Lazy๋‚˜ dynamic import๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ–ˆ๋‹ค

import dynamic from 'next/dynamic'

const DynamicComponent = dynamic(() => import('../components/hello'))
  • ํ•˜์ง€๋งŒ RSC์—์„œ RCC๋ฅผ importํ•˜๋Š” ์ผ€์ด์Šค์—์„œ๋Š” ์ž๋™์ ์œผ๋กœ RCC๋ฅผ dynamic importํ•˜๊ฒŒ ๋œ๋‹ค
  • RCC๋Š” ์„œ๋ฒ„์—์„œ ํ•ด์„ํ•˜์ง€ ์•Š๊ณ , placeholder๋งŒ ๋‚จ๊ฒจ๋‘”๋‹ค๊ณ  ํ–ˆ๋Š”๋ฐ, ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ๊ตณ์ด RSC๊ฐ€ ๋ Œ๋”๋ง๋  ๋•Œ RCC๋ฅผ ์ฆ‰์‹œ importํ•  ํ•„์š”๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค

 

Progressive Rendering


Next 13๋ถ€ํ„ฐ๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์„œ๋ฒ„์—์„œ ํ•œ์ฐจ๋ก€ ๋ Œ๋”๋ง๋˜๋ฉฐ, ๊ทธ ๊ฒฐ๊ณผ๋ฌผ๋กœ ์ง๋ ฌํ™”๋œ JSON์ด ์ƒ์„ฑ๋œ๋‹ค๊ณ  ํ–ˆ๋‹ค

  • ๊ทธ๋ฆฌ๊ณ  ํด๋ผ์ด์–ธํŠธ๋Š” ๊ทธ ๊ฒฐ๊ณผ๋ฌผ์„ Stream์˜ ํ˜•ํƒœ๋กœ ์ˆ˜์‹ ํ•˜๊ฒŒ ๋œ๋‹ค
// Tweets.server.js
import { fetch } from 'react-fetch' // React's Suspense-aware fetch()
import Tweet from './Tweet.client'
export default function Tweets() {
  const tweets = fetch(`/tweets`).json()
  return (
    <ul>
      {tweets.slice(0, 2).map((tweet) => (
        <li>
          <Tweet tweet={tweet} />
        </li>
      ))}
    </ul>
  )
}

// Tweet.client.js
export default function Tweet({ tweet }) {
  return <div onClick={() => alert(`Written by ${tweet.username}`)}>{tweet.body}</div>
}

// OuterServerComponent.server.js
export default function OuterServerComponent() {
  return (
    <ClientComponent>
      <ServerComponent />
      <Suspense fallback={'Loading tweets...'}>
        <Tweets />
      </Suspense>
    </ClientComponent>
  )
}
M1:{"id":"./src/ClientComponent.client.js","chunks":["client1"],"name":""}
S2:"react.suspense"
J0:["$","@1",null,{"children":[["$","span",null,{"children":"Hello from server land"}],["$","$2",null,{"fallback":"Loading tweets...","children":"@3"}]]}]
M4:{"id":"./src/Tweet.client.js","chunks":["client8"],"name":""}
J3:["$","ul",null,{"children":[["$","li",null,{"children":["$","@4",null,{"tweet":{...}}}]}],["$","li",null,{"children":["$","@4",null,{"tweet":{...}}}]}]]}]
  • ์œ„ ๋ฌธ์ž์—ด์€ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ˆ˜์‹ ํ•˜๋Š” ์ŠคํŠธ๋ฆผ์˜ ํ•œ ์˜ˆ์‹œ๋ฅผ ๋‚˜ํƒ€๋‚ธ ๊ฒƒ์ด๋‹ค.
  • ์—ฌ๊ธฐ์„œ ์งš๊ณ  ๋„˜์–ด๊ฐˆ ๋ถ€๋ถ„์€ ๋ฐ์ดํ„ฐ๊ฐ€ ‘์ŠคํŠธ๋ฆผ’ ํ˜•ํƒœ๋กœ ์ „๋‹ฌ๋œ๋‹ค๋Š” ์‚ฌ์‹ค์ด๋‹ค.
  • ์ฆ‰, ์Šคํฌ๋ฆฐ์˜ ๋ชจ๋“  ํ™”๋ฉด์ •๋ณด๋ฅผ ์ˆ˜์‹ ํ•  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆด ํ•„์š” ์—†์ด, ํด๋ผ์ด์–ธํŠธ๋Š” ๋จผ์ € ์ˆ˜์‹ ๋œ ๋ถ€๋ถ„๋ถ€ํ„ฐ ๋ฐ˜์˜ํ•˜๊ธฐ ์‹œ์ž‘ํ•˜์—ฌ ํ™”๋ฉด์— ๋„์›Œ์ค„ ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.
  • ์œ„ ์ŠคํŠธ๋ฆผ ๋ฌธ์ž์—ด์„ ๋ณด๋ฉด S2 ์ง€์ ์— suspense๊ฐ€ ์„œ์ˆ ๋˜์–ด ์žˆ๋‹ค.
  • ๊ทธ๋ฆฌ๊ณ  J0๋ฅผ ๋ณด๋ฉด ๋’ค์ชฝ์— children์œผ๋กœ “@3”์ด ์ฐธ์กฐ๋˜์–ด ์žˆ๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.
  • ํ•˜์ง€๋งŒ ์ŠคํŠธ๋ฆผ์˜ ์–ด๋””๋ฅผ ๋ด๋„ “@3”์— ๋Œ€ํ•œ ์ •์˜๋Š” ๋‚˜์™€์žˆ์ง€ ์•Š๋‹ค.
  • ์ด๋Š”, ์•„์ง data fetch๊ฐ€ ์™„๋ฃŒ๋˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— fallback์ด ๋ณด์—ฌ์ง€๋Š” ์ƒํ™ฉ์ด๊ธฐ ๋•Œ๋ฌธ์— @3๋ฅผ placehoder๋กœ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
  • ๋งŒ์•ฝ data fetch๊ฐ€ ์™„๋ฃŒ๋˜๋ฉด “@3”์ด “J3”๋กœ ๋Œ€์ฒด๋˜๊ณ , “J3”๋Š” ์ฐธ์กฐํ•˜๊ณ  ์žˆ๋˜ “M4”์— ํ•ด๋‹นํ•˜๋Š” client component์— data๋ฅผ ๋„˜๊ฒจ์ฃผ๋ฉด์„œ ํ™”๋ฉด์— ๋ณด์—ฌ์ง€๊ฒŒ ๋œ๋‹ค.
  • ๋”ฐ๋ผ์„œ RSC๋ฅผ React.Suspense์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ๊ธฐ๋‹ค๋ฆด ํ•„์š” ์—†์ด ๋จผ์ € ๊ทธ๋ฆด ์ˆ˜ ์žˆ๋Š” ๋ถ€๋ถ„์„ ๋ฐ˜์˜ํ•˜์—ฌ ๋ทฐ๋ฅผ ๋กœ๋“œํ•œ ๋’ค, data fetch๊ฐ€ ์™„๋ฃŒ๋˜๋ฉด ๊ทธ ๊ฒฐ๊ณผ๊ฐ€ ์ฆ‰๊ฐ์ ์œผ๋กœ ์ŠคํŠธ๋ฆผ์— ๋ฐ˜์˜๋จ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

 

์ปดํฌ๋„ŒํŠธ ๋‹จ์œ„ refetch


์ „ํ†ต์ ์ธ SSR์˜ ๊ฒฝ์šฐ์—๋Š” ์™„์„ฑ๋œ HTML์„ ๋‚ด๋ ค์ฃผ๊ธฐ ๋•Œ๋ฌธ์—, ์ž‘์€ ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ๋ฐœ์ƒํ•˜๋”๋ผ๋„ ์ „์ฒด ํŽ˜์ด์ง€๋ฅผ ์ „๋ถ€ ์ƒˆ๋กœ ๊ทธ๋ ค์„œ ๋ฐ›์•„์™€์•ผ ํ–ˆ๋‹ค

  • ๋ฐ˜๋ฉด RSC๋Š” ์ตœ์ข… ๊ฒฐ๊ณผ๋ฌผ์ด ์™„์„ฑ๋œ HTML์ด ์•„๋‹ˆ๋ผ, ์ง๋ ฌํ™”๋œ ์ŠคํŠธ๋ฆผ์˜ ํ˜•ํƒœ๋กœ ๋ฐ›์•„์˜ค๊ธฐ ๋•Œ๋ฌธ์—, ํด๋ผ์ด์–ธํŠธ์—์„œ ์ŠคํŠธ๋ฆผ์„ ํ•ด์„ํ•˜์—ฌ virtualDOM์„ ํ˜•์„ฑํ•˜๊ณ , Reconciliation์„ ํ†ตํ•ด ๋ทฐ๋ฅผ ๊ฐฑ์‹ ํ•˜๋Š” ๊ณผ์ •์„ ๊ฑฐ์น˜๊ฒŒ ๋œ๋‹ค
  • ํ™”๋ฉด์— ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ์ƒ๊ฒจ์„œ ์„œ๋ฒ„์—์„œ ์ƒˆ๋กœ์šด ์ •๋ณด๋ฅผ ๋ฐ›์•„์™€์•ผ ํ•˜๋Š” ์ƒํ™ฉ์ด ์ƒ๊ธฐ๋”๋ผ๋„, ์ƒˆ๋กœ์šด ์Šคํฌ๋ฆฐ์œผ๋กœ ๊ฐˆ์•„๋ผ์šฐ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๊ธฐ์กด ํ™”๋ฉด์˜ State ๋“ฑ Context๋ฅผ ์œ ์ง€ํ•œ ์ฑ„๋กœ ๋ณ€๊ฒฝ๋œ ์‚ฌํ•ญ๋งŒ์„ ์„ ํƒ์ ์œผ๋กœ ๋ฐ˜์˜ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค

 

๋Š๋‚€์ 


Next์˜ ๋ Œ๋”๋ง ๊ณผ์ •์„ ์กฐ๊ธˆ ๋” ๊นŠ๊ฒŒ ๊ณต๋ถ€ํ•ด๋ณด๋ฉด์„œ ๋Š๋‚€ ์ 

  • RSC์™€ SSR์ด ์™„์ „ํžˆ ๊ตฌ๋ถ„๋˜๋Š” ๊ฐœ๋…์ด๋ผ๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์ƒˆ๋กญ๊ฒŒ ์•Œ๊ฒŒ ๋œ ๊ฐœ๋…์ด์—ˆ๋‹ค
    • Next๋Š” ์ด ๋‘˜์„ ์ ์ ˆํžˆ ์กฐํ™”์‹œ์ผœ์„œ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋” ํฐ ์‹œ๋„ˆ์ง€๋ฅผ ๋งŒ๋“ค์–ด๋‚ธ๋‹ค
  • ๋‹จ์ˆœํžˆ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์—์„œ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” child props๋กœ ์ „๋‹ฌํ•˜๋ผ๋Š” ์–˜๊ธฐ๋งŒ ์•Œ๊ณ  ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์—ˆ๋Š”๋ฐ, ์ด์ œ๋Š” ๊ทธ ์ด์œ ๋ฅผ ์•Œ๊ฒŒ ๋˜์—ˆ๋‹ค

๊ฒฐ๋ก : Next ์™ธ์•Š์”€?

 

Reference


 

Next) ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ(React Server Component)์— ๋Œ€ํ•œ ๊ณ ์ฐฐ

์ด๋ฒˆ์— ํšŒ์‚ฌ์—์„œ ์‹ ๊ทœ ์›น ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ–ˆ๋Š”๋ฐ, ์ •๋ง ๋œฌ๊ธˆ ์—†๊ฒŒ๋„ ์•ฑ ๊ฐœ๋ฐœ์ž์ธ ๋‚ด๊ฐ€ ์ด ํ”„๋กœ์ ํŠธ๋ฅผ ๋ฆฌ๋“œํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค. ์‚ฌ์‹ค ์–ต์ง€๋กœ ๋– ๋งก๊ฒŒ ๋œ ๊ฒƒ์€ ์•„๋‹ˆ๊ณ , ์ƒˆ๋กœ์šด ์›น ๊ธฐ์ˆ  ์Šคํƒ์„

velog.io

 

[๋ฒˆ์—ญ] React Server vs Client Component in Next.js 13

์› ๊ธ€ ๋งํฌNext.js ์—์„œ, ๋„ˆ๋Š” ๋ฆฌ์•กํŠธ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ์™€ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. app ๊ฒฝ๋กœ์—์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๋“ค์€ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ์ด๋‹ค. ์ด ๊ฒŒ์‹œ๊ธ€์—์„œ, ์šฐ๋ฆฌ๋Š” ๋ฆฌ์•กํŠธ ์„œ

velog.io

 

React(๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ)

๋ฉ”ํƒ€ ์—์„œ ๊ฐœ๋ฐœํ•œ ์˜คํ”ˆ ์†Œ์Šค ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ . ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž ์‚ฌ์ด์—์„œ AngularJS ,

namu.wiki

 

728x90