[Next.js] Hydration

Janeยท2023๋…„ 8์›” 23์ผ
27

Next.js

๋ชฉ๋ก ๋ณด๊ธฐ
4/12
post-thumbnail
post-custom-banner
  • Next.js์—์„œ๋Š” ์„ธ ๊ฐ€์ง€ ๋ฐฉ์‹์˜ ๋ Œ๋”๋ง ๋ฐฉ์‹(SSR, SSG, CSR)์„ ๋ชจ๋‘ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ–ฅ๏ธ CSR

  • React์—์„œ๋Š” CSR ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ์ฒ˜์Œ์—๋Š” ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋นˆ HTML ํŒŒ์ผ์„ ๋ฐ›์•„ ํ™”๋ฉด์—๋Š” ์•„๋ฌด๊ฒƒ๋„ ๋‚˜ํƒ€๋‚˜์ง€ ์•Š๋‹ค๊ฐ€, ์‚ฌ์šฉ์ž์˜ ๊ธฐ๊ธฐ์—์„œ ๋ Œ๋”๋ง์ด ์™„๋ฃŒ๋˜๋ฉด ํ•œ ๋ฒˆ์— ํ™”๋ฉด์„ ๋ณด์—ฌ์ค€๋‹ค.
// index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Title</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>
  • ๋‹จ์ˆœ ๊ตฌ์กฐ๋งŒ ์žˆ๋Š” HTML ๋ฌธ์„œ์™€ JS ํŒŒ์ผ๋“ค์„ ๋ชจ๋‘ ํด๋ผ์ด์–ธํŠธ์— ๋ณด๋‚ธ ๋’ค Client-Side์—์„œ JS ๋กœ๋“œ๋“ค์„ ํ†ตํ•ด ์›น ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”๋งํ•œ๋‹ค.
  • ์›น ํŽ˜์ด์ง€๊ฐ€ ๋ Œ๋”๋ง ๋œ ์ดํ›„์—๋„ ํŽ˜์ด์ง€ ๋‚ด์—์„œ ๋™์ž‘ํ•˜๋Š” ๋ชจ๋“  ์ด๋ฒคํŠธ๋Š” JS๋ฅผ ํ†ตํ•ด ๋ฐœ์ƒํ•œ๋‹ค.
// index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./src/App";

ReactDOM.render(<App />, document.getElementById("root"));
  • ๊ธฐ๋ณธ ๋ผˆ๋Œ€๋งŒ ์žˆ๋Š” index.html ํŒŒ์ผ ๋Œ€์‹  src/index.js์˜ JS ์ฝ”๋“œ์—์„œ ๋ชจ๋“  ํ™”๋ฉด์„ ๋ Œ๋”๋งํ•œ ๋’ค HTML์˜ DOM ์š”์†Œ ์ค‘ root๋ผ๋Š” ID๋ฅผ ๊ฐ€์ง„ element๋ฅผ ์ฐพ์•„ ํ•˜์œ„์— ๋‚ด์šฉ์„ ์ฃผ์ž…ํ•œ๋‹ค.

  • Next.js์—์„œ CSR ์‚ฌ์šฉํ•˜๊ธฐ

๐Ÿ–ผ๏ธ Pre-Rendering

  • SSR๊ณผ SSG๋Š” Pre-Rendering ์ด๋ผ๊ณ  ๋ถˆ๋ฆฌ๊ธฐ๋„ ํ•œ๋‹ค.
    • ์ถ”๊ฐ€ ๋ฐ์ดํ„ฐ์˜ fetching๊ณผ React ์ปดํฌ๋„ŒํŠธ์˜ HTML๋กœ์˜ ๋ณ€ํ™˜์ด ๋ Œ๋”๋ง ๊ฒฐ๊ณผ๋ฌผ์ด ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์ „์†ก๋˜๊ธฐ ์ „์— ๋ฐœ์ƒํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
    • Next.js์—์„œ์˜ SSR, SSG
  • ๊ทธ๋ฆฌ๊ณ  Next.js์—์„œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ชจ๋“  ํŽ˜์ด์ง€๋ฅผ ๋ฏธ๋ฆฌ ๋ Œ๋”๋งํ•œ๋‹ค.
  • ์‚ฌ์šฉ์ž์˜ ๊ธฐ๊ธฐ์—์„œ JS๊ฐ€ ๋ชจ๋“  ์ผ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋Œ€์‹  ์„œ๋ฒ„์—์„œ ๋จผ์ € HTML ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ๋ Œ๋”๋ง ์ž‘์—…์ด ์ง„ํ–‰๋˜๋Š” ๋™ํ•œ ์‚ฌ์šฉ์ž์—๊ฒŒ ํ•ด๋‹น ํŽ˜์ด์ง€์— ํ•„์š”ํ•œ HTML ํ™”๋ฉด์ด ๋ณด์—ฌ์ง„๋‹ค.

ํ•˜์ง€๋งŒ ์—ฌ๊ธฐ์„œ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ!

๐Ÿฆด ํ˜„์žฌ๋Š” ๋นˆ ๊ป๋ฐ๊ธฐ๋งŒ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค!

  • ์ด๋•Œ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ฐ›๋Š” ์›น ํŽ˜์ด์ง€๋Š” ๋‹จ์ˆœํžˆ ์›น ํ™”๋ฉด์„ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•œ HTML์ผ ๋ฟ์ด๊ณ , ๋™์ž‘์— ํ•„์š”ํ•œ JS ์š”์†Œ๋Š” ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • ํŠน์ • JS ๋ชจ๋“ˆ ๋ฟ ์•„๋‹ˆ๋ผ ๋‹จ์ˆœ ํด๋ฆญ๊ณผ ๊ฐ™์€ ์ด๋ฒคํŠธ๋“ค์ด ๊ฐ ์›น ํŽ˜์ด์ง€์˜ DOM ์š”์†Œ์— ์ ์šฉ๋˜์–ด ์žˆ์ง€ ์•Š์€ ์ƒํƒœ์˜ ํŽ˜์ด์ง€๊ฐ€ ์ „์†ก๋˜๋Š” ๊ฒƒ์ด๋‹ค.
  • useEffect์ฒ˜๋Ÿผ ๋งˆ์šดํŠธ ๋œ ํ›„ ์‹คํ–‰๋˜๋Š” ๋™์ž‘๋“ค ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ onClick, onChange์™€ ๊ฐ™์€ ๋ฐ”์ธ๋”ฉ๋„ ๋น ์ ธ ์žˆ๋Š” ์ƒํƒœ์ด๋‹ค.

๐Ÿง ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์„๊นŒ์š”?

  • Next.js ์„œ๋ฒ„์—์„œ๋Š” Pre-Rendering ๋œ ์›น ํŽ˜์ด์ง€๋ฅผ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋ณด๋‚ธ ๋’ค, ๋ฐ”๋กœ React๊ฐ€ ๋ฒˆ๋“ค๋ง ๋œ JS ์ฝ”๋“œ๋“ค์„ Chunk ๋‹จ์œ„๋กœ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์ „์†กํ•œ๋‹ค.
  • ๊ทธ๋ฆฌ๊ณ  ์ด๋Ÿฌํ•œ JS ์ฝ”๋“œ๋“ค์ด ์ด์ „์— ์ „์†ก๋œ HTML DOM ์š”์†Œ ์œ„๋กœ ๋ฆฌ๋ Œ๋”๋ง ๋˜๋Š” ๊ณผ์ • ์†์—์„œ ์ž๊ธฐ ์ž๋ฆฌ๋ฅผ ์ฐพ์•„ ๋งค์นญ๋œ๋‹ค.

๐Ÿ“ข ๊ทธ๋ฆฌ๊ณ  ์šฐ๋ฆฌ๋Š” ์ด๋Ÿฌํ•œ ๊ณผ์ •์„ "Hydration"์ด๋ผ ๋ถ€๋ฆ…๋‹ˆ๋‹ค!

๐Ÿšฟ Hydration

  • Server-Side์—์„œ ๋ Œ๋”๋ง ๋œ ์ •์  ํŽ˜์ด์ง€(HTML)์™€ ๋ฒˆ๋“ค๋ง ๋œ JS ํŒŒ์ผ์„ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋ณด๋‚ด๋ฉด, Client-Side์—์„œ HTML ์ฝ”๋“œ์™€ JS(React) ์ฝ”๋“œ๋ฅผ ์„œ๋กœ ๋งค์นญ์‹œํ‚ค๋Š” ๊ณผ์ •

Hydration ์€ ์ˆ˜๋ถ„ ๊ณต๊ธ‰์ด๋ผ๋Š” ์˜๋ฏธ๋ฅผ ๊ฐ–๋Š”๋‹ค.

  • JS ์ฝ”๋“œ๋“ค์ด DOM ์š”์†Œ ์œ„์— ๋ฌผ์„ ์ฑ„์šฐ๋“ฏ ํ•„์š”๋กœ ํ•˜๋˜ ์š”์†Œ๋“ค์„ ์ฑ„์šด๋‹คํ•˜์—ฌ ๋ถ™์—ฌ์ง„ ์ด๋ฆ„์ด๋ผ๊ณ  ํ•œ๋‹ค.

๐Ÿ‘ฉโ€๐Ÿซ ์ˆ˜๋ถ„๊ธฐ ์—†๋Š” ์ •์  ์›น ํŽ˜์ด์ง€์— ๋ฌผ์„ ์ฃผ๋Š” ๋Š๋‚Œ์ด๋ผ๊ณ  ์ดํ•ดํ•ฉ์‹œ๋‹ค!

๐ŸŒŸ Hydration์˜ ์ง„ํ–‰ ๊ณผ์ •

  1. React๋กœ ํŽ˜์ด์ง€๋ฅผ ์ œ์ž‘ํ•œ๋‹ค.
  2. Next.js๋‚˜ Gatsby์™€ ๊ฐ™์€ ํ”„๋ ˆ์ž„์›Œํฌ๋Š” React์—์„œ HTML ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•œ React Server-Side API์ธ ReactDOMServer์„ ์‚ฌ์šฉํ•ด ์ œ์ž‘๋œ ์‚ฌ์ดํŠธ์˜ ํ”„๋กœ๋•์…˜ ๋‹จ๊ณ„ ํŒŒ์ผ์„ ์ƒ์„ฑํ•œ๋‹ค.
  3. ๋งŒ์•ฝ ์ด๋•Œ ์›น ํŽ˜์ด์ง€๋ฅผ ๋ณด๊ฒŒ ๋œ๋‹ค๋ฉด, ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ์ƒ์„ฑ๋œ ์ •์ ์ธ HTML ํŒŒ์ผ์„ ๋ณด๊ฒŒ ๋  ๊ฒƒ์ด๋‹ค.
  4. ํŽ˜์ด์ง€ ์ฒซ ๋กœ๋”ฉ ์ดํ›„ JS๊ฐ€ ๋กœ๋“œ ๋˜๊ณ , ReactDOM.hydrate() API๋Š” JS์™€ ํ•จ๊ป˜ ์„œ๋ฒ„์—์„œ ๋ Œ๋”๋ง๋˜์—ˆ๋˜ HTML ํŽ˜์ด์ง€์— ์ˆ˜๋ถ„์„ ๊ณต๊ธ‰ํ•œ๋‹ค.
  5. Hydration ์ดํ›„, React reconciler API๊ฐ€ ์ž๋ฆฌ๋ฅผ ๋Œ€์ฒดํ•˜๊ณ , ์‚ฌ์ดํŠธ๋Š” ์ƒํ˜ธ์ž‘์šฉ์ด ๊ฐ€๋Šฅํ•ด์ง„๋‹ค.
  • hydration์ด ์ ์šฉ๋˜๋ฉด ํด๋ฆญ ๋“ฑ์˜ ์ด๋ฒคํŠธ๋‚˜ ๋ชจ๋“ˆ๋“ค์ด ์ ์šฉ๋˜์–ด ์‚ฌ์šฉ์ž ์กฐ์ž‘์ด ๊ฐ€๋Šฅํ•ด์ง„๋‹ค!
  • ์‚ฌ์šฉ์ž๋Š” SSR์„ ํ†ตํ•ด UI๋ฅผ ๋ฏธ๋ฆฌ ๋ณด๊ณ , Hydration์„ ํ†ตํ•ด ํŽ˜์ด์ง€ ์กฐ์ž‘์ด ๊ฐ€๋Šฅํ•ด์ง€๋Š” ๊ฒƒ์ด๋‹ค.

๐Ÿง ๋‘ ๋ฒˆ์”ฉ์ด๋‚˜ ๋ Œ๋”๋ง๋˜๋ฉด ๋น„ํšจ์œจ์ ์ด์ง€ ์•Š๋‚˜์š”?

  • Server-Side์—์„œ Pre-Rendering ๋œ ๋ฌธ์„œ๋Š” ๋ชจ๋“  JS ์š”์†Œ๋“ค์ด ๋ฐฐ์ œ๋œ ๊ต‰์žฅํžˆ ๊ฐ€๋ฒผ์šด ํŒŒ์ผ์ด๋ฏ€๋กœ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋น ๋ฅด๊ฒŒ ๋กœ๋“œ๋˜๋Š” ์›น ํŽ˜์ด์ง€๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ์ด๋Š” ๊ฐ™์€ ํ™”๋ฉด์— ๋‘ ๋ฒˆ ๋ Œ๋”๋ง์ด ๋ฐœ์ƒํ•œ๋‹ค๋Š” ๋‹จ์ ์„ ์ถฉ๋ถ„ํžˆ ๋ณด์™„ํ•  ์ˆ˜ ์žˆ๋Š” ์žฅ์ ์ด๋‹ค.
  • ๋” ๋‚˜์•„๊ฐ€, Client-Side์—์„œ JS ํŒŒ์ผ์ด ๋ Œ๋”๋ง ๋  ๋•Œ, ๋‹จ์ง€ ๊ฐ DOM ์š”์†Œ์— JS ์†์„ฑ์„ ๋งค์นญ์‹œํ‚ฌ ๋ฟ ์‹ค์ œ ์›น ํŽ˜์ด์ง€๋ฅผ ๋‹ค์‹œ ๊ทธ๋ฆฌ๋Š” paint() ํ•จ์ˆ˜๊นŒ์ง€ ํ˜ธ์ถœํ•˜์ง€๋Š” ์•Š๋Š”๋‹ค.

๐Ÿง Hydration์€ Next.js์—์„œ๋งŒ ๋ฐœ์ƒํ•˜๋‚˜์š”?

๐Ÿ‘ฉโ€๐Ÿซ ์•„๋‹™๋‹ˆ๋‹ค!
  • Hydration์€ Next.js๋งŒ์˜ ํŠน๋ณ„ํ•œ ๋™์ž‘์ด ์•„๋‹ˆ๋ผ ReactDOM ํ•จ์ˆ˜์ด๋‹ค.
  • React: View๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
  • ReactDOM
    • UI๋ฅผ ์‹ค์ œ๋กœ ๋ธŒ๋ผ์šฐ์ €์— ๋ Œ๋”๋งํ•  ๋•Œ ์‚ฌ์šฉ๋˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
    • ์ตœ์ƒ์œ„ app์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” DOM ๊ด€๋ จ ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

โš™๏ธ ReactDOM.hydrate()

ReactDOM.render()

ReactDOM.render(element, container, [callback]);
  • ReactDOM.render() ํ•จ์ˆ˜๋Š” ํŠน์ • ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‘ ๋ฒˆ์งธ ์ธ์ž๋กœ ์ง€์ •๋œ DOM ์š”์†Œ์— ํ•˜์œ„๋กœ ์ฃผ์ž…ํ•˜์—ฌ ๋ Œ๋”๋ง์„ ์ฒ˜๋ฆฌํ•ด์ฃผ๋Š” ํ•จ์ˆ˜์ด๋‹ค.
  • ์ œ๊ณต๋œ container์— element๋ฅผ ๋ Œ๋”๋งํ•˜๊ณ , component์— ๋Œ€ํ•œ ์ฐธ์กฐ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • ๋งŒ์•ฝ ์ด์ „์— element๊ฐ€ container์— ๋ Œ๋”๋ง ๋์—ˆ๋‹ค๋ฉด, ReactDOM์„ ์—…๋ฐ์ดํŠธํ•˜๊ณ , ์ตœ์ข… React element์˜ ๋ฐ˜์˜์ด ํ•„์š”ํ•  ๋•Œ์—๋งŒ DOM์„ ๋ณ€๊ฒฝํ•œ๋‹ค.
  • ๋ Œ๋”๋ง์ด ์™„๋ฃŒ๋˜๋ฉด ํŠน์ • ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์„ธ ๋ฒˆ์งธ ์ธ์ž๋กœ ๋„˜๊ฒจ์ค„ ์ˆ˜ ์žˆ๋‹ค.
  • container node๋ฅผ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ  ์ž์‹๋งŒ ์ˆ˜์ •ํ•œ๋‹ค.
  • ๊ธฐ์กด ์ž์‹์„ ๋ฎ์–ด์“ฐ์ง€ ์•Š๊ณ  ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์‚ฝ์ž…ํ•œ๋‹ค.

ReactDOM.hydrate()

ReactDOM.hydrate(element, container, [callback]);
  • render() ๋ฉ”์„œ๋“œ์™€ ๋™์ผํ•˜์ง€๋งŒ ReactDOMServer์—์„œ HTML ์ปจํ…์ธ ๋ฅผ ๋ Œ๋”๋งํ•œ container๋ฅผ hydrateํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋œ๋‹ค.
  • SSR์„ ํ†ตํ•ด ์ด๋ฏธ ๋งˆํฌ์—…์ด ์ฑ„์›Œ์ ธ ์žˆ๋Š” ๊ฒฝ์šฐ ๋‹ค์‹œ ๋ Œ๋”๋งํ•  ํ•„์š”๊ฐ€ ์—†์œผ๋ฏ€๋กœ hydrate๋ฅผ ํ†ตํ•ด ๊ธฐ์กด ๋งˆํฌ์—…์— ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ ๋“ฑ๋งŒ ์ถ”๊ฐ€ํ•œ๋‹ค.
  • ํŠน์ • ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‘ ๋ฒˆ์งธ ์ธ์ž๋กœ ์ง€์ •๋œ DOM ์š”์†Œ์— ํ•˜์œ„๋กœ hydrate ์ฒ˜๋ฆฌํ•œ๋‹ค.
  • ๋ Œ๋”๋ง์„ ํ†ตํ•ด ์ƒˆ๋กœ์šด ์›น ํŽ˜์ด์ง€๋ฅผ ๊ตฌ์„ฑํ•  DOM์„ ์ƒ์„ฑํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • ๋Œ€์‹ , ๊ธฐ์กด DOM tree์—์„œ ํ•ด๋‹น๋˜๋Š” DOM ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ฐพ์•„ ์ •ํ•ด์ง„ JS ์†์„ฑ(์˜ˆ: eventListener)๋งŒ ๋ถ€์ฐฉ์‹œํ‚จ๋‹ค.

๋™์ž‘ ๊ณผ์ •

  1. ์„œ๋ฒ„์—์„œ ๋ฐ›์•„์˜จ DOM tree์™€ ์ž์ฒด์ ์œผ๋กœ ๋ Œ๋”๋งํ•œ tree๋ฅผ ๋น„๊ตํ•œ๋‹ค.
  2. ๋‘ tree ์‚ฌ์ด์˜ ์ฐจ์ด์ ์„ ์–ป์€ ํ›„, ์ž์ฒด์ ์œผ๋กœ Client-Side-Renderingํ•œ tree์™€ ๋น„๊ตํ•˜๋ฉฐ ์–ด๋–ค DOM๊ณผ ๋งค์นญ๋˜๋Š”์ง€ ์ดํ•ดํ•œ๋‹ค.
  3. ์ดํ•ดํ•œ ๋‚ด์šฉ์— ๋”ฐ๋ผ ํด๋ผ์ด์–ธํŠธ ๋ Œ๋”๋ง ๋™์ž‘์„ ์ง„ํ–‰ํ•œ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์—ฌ๊ธฐ์„œ ๋˜ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ!

๐Ÿ‘ฉ ๊ทธ๋งŒํ•ด๋ผ!

๐Ÿšจ SSR๊ณผ Hydration์˜ ๋ฌธ์ œ์ 

โš ๏ธ ๋ณด์—ฌ์ฃผ๊ธฐ ์ „ ๋ชจ๋“  ๊ฒƒ์„ ๋‹ค ๊ฐ€์ ธ์™€์•ผ ํ•ฉ๋‹ˆ๋‹ค!

  • SSR์€ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฐ์ดํ„ฐ๊ฐ€ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๊ฒƒ์„ ํ—ˆ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค.

๐Ÿค” ์ข‹์€ ๊ฑฐ ์•„๋‹Œ๊ฐ€์š”?
  • ์ด๋Š” ๊ณง ํ˜„์žฌ ์ œ๊ณต๋˜๋Š” API๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” HTML์— ๋ Œ๋”๋งํ•  ๋•Œ ์„œ๋ฒ„ ์ธก์—์„œ ์ปดํฌ๋„ŒํŠธ์— ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ชจ๋‘ ์ค€๋น„ํ•ด๋‘์–ด์•ผ ํ•จ์„ ์˜๋ฏธํ•œ๋‹ค.
  • ํด๋ผ์ด์–ธํŠธ์— HTML ํŒŒ์ผ์„ ๋ณด๋‚ด๊ธฐ ์ „ Server-Side์—์„œ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ๋ชจ์•„๋‘์–ด์•ผ ํ•˜๋Š” ๊ฒƒ์€ ๋งค์šฐ ๋น„ํšจ์œจ์ ์ด๋‹ค.
  • ์˜ˆ๋ฅผ ๋“ค์–ด, ๋Œ“๊ธ€์ด ์žˆ๋Š” ๊ธ€์„ ๋ Œ๋”๋งํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž.
    • ๋Œ“๊ธ€์€ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋ณด์—ฌ์งˆ ํ•„์š”๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ, Server-Side HTML ์ถœ๋ ฅ๋ฌผ์— ํฌํ•จํ•˜๋ ค ํ•œ๋‹ค.
    • ํ•˜์ง€๋งŒ DB๋‚˜ API์˜ ์‘๋‹ต ์†๋„๋ฅผ ์กฐ์ ˆํ•  ์ˆ˜ ์—†๋Š” ์ƒํ™ฉ์—์„œ, ๊ฐœ๋ฐœ์ž๋Š” ๋‘ ๊ฐ€์ง€ ์ค‘ ํ•˜๋‚˜๋ฅผ ์„ ํƒํ•ด์•ผ ํ•œ๋‹ค.
    • HTML ์ถœ๋ ฅ๋ฌผ์—์„œ ์ œ์™ธ์‹œํ‚ฌ ๊ฒฝ์šฐ ์‚ฌ์šฉ์ž๋Š” JS ํŒŒ์ผ์ด ์™„์ „ํžˆ ๋ถˆ๋Ÿฌ์™€์ง€๊ธฐ ์ „๊นŒ์ง€๋Š” ๋Œ“๊ธ€์„ ๋ณผ ์ˆ˜ ์—†๋‹ค.
    • HTML ์ถœ๋ ฅ๋ฌผ์— ํฌํ•จ์‹œํ‚ฌ ๊ฒฝ์šฐ ๋Œ“๊ธ€์ด ๋ถˆ๋Ÿฌ์™€์ง€๊ณ  ์ „์ฒด tree๊ฐ€ ๋ Œ๋”๋ง๋  ๋–„๊นŒ์ง€ ์‚ฌ์šฉ์ž๋Š” ๋‚˜๋จธ์ง€ HTML ํŒŒ์ผ๊นŒ์ง€ ์ „์†ก๋ฐ›์ง€ ๋ชปํ•œ๋‹ค.

โš ๏ธ Hydration์„ ์œ„ํ•ด์„œ๋Š” ๋ชจ๋“  ๊ฒƒ์„ ๋‹ค ๋ถˆ๋Ÿฌ์™€์•ผ ํ•ฉ๋‹ˆ๋‹ค!

  • React๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•˜๋Š” ๊ณผ์ •์—์„œ Server-Side์—์„œ ์ƒ์„ฑ๋œ HTML ํŒŒ์ผ์„ ์ˆœํšŒํ•˜๋ฉฐ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋ถ€์ฐฉ์‹œํ‚จ๋‹ค.
    • ์ด๊ฒŒ ๋™์ž‘ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ƒ์„ฑํ•œ tree๊ฐ€ ์„œ๋ฒ„์—์„œ ์ƒ์„ฑํ•œ tree์™€ ์ผ์น˜ํ•ด์•ผ ํ•œ๋‹ค.
    • Hydration์€ ๋‹จ์ผ ์ž‘์—…๋งŒ ๊ฐ€๋Šฅํ•˜๋ฏ€๋กœ, ๋”ฐ๋กœ ๋กœ๋“œํ•˜๋ ค ํ•  ๊ฒฝ์šฐ React๋Š” HTML ์ฝ”๋“œ์˜ ์ผ๋ถ€๋ถ„๋งŒ์œผ๋กœ๋Š” ๋ฌด์—‡์„ ํ•ด์•ผ ํ• ์ง€ ์•Œ ์ˆ˜ ์—†์–ด Hydration์—์„œ ํ•ด๋‹น ์ฝ”๋“œ๋ฅผ ์‚ญ์ œํ•˜๊ฒŒ ๋œ๋‹ค.
  • ์œ„์˜ ์˜ˆ์‹œ์—์„œ, ํŽ˜์ด์ง€์—๋Š” ๋Œ“๊ธ€ ๋ถ€๋ถ„๋ง๊ณ ๋„ Nav Bar, Side Bar ๋“ฑ์— ์‚ฌ์šฉ๋œ JS ์ฝ”๋“œ๋“ค์ด ์กด์žฌํ•  ๊ฒƒ์ด๋‹ค.
    • ํ•˜์ง€๋งŒ ๋Œ“๊ธ€์— ๋Œ€ํ•œ ์ฝ”๋“œ๊ฐ€ ๋ถˆ๋Ÿฌ์™€์ง€๊ธฐ ์ „๊นŒ์ง€๋Š” ๋‹ค๋ฅธ ๋ถ€๋ถ„์— ๋Œ€ํ•ด์„œ๋„ Hydration์„ ์ง„ํ–‰ํ•  ์ˆ˜ ์—†๋‹ค.

โš ๏ธ ์ƒํ˜ธ์ž‘์šฉ์„ ํ•˜๊ธฐ ์ „ ๋ชจ๋“  ํ•ญ๋ชฉ์— ๋Œ€ํ•œ Hydration์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค!

  • React๋Š” ํ•œ ๋ฒˆ์˜ ์ž‘์—…์„ ํ†ตํ•ด tree์— ๋Œ€ํ•œ Hydration์„ ์ง„ํ–‰ํ•œ๋‹ค.
    • ๋‹ค์‹œ ๋งํ•ด, ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ณผ์ •์ด ํ•œ ๋ฒˆ ์‹œ์ž‘๋˜๋ฉด React๋Š” ์ „์ฒด tree์— ๋Œ€ํ•ด ์ด ๊ณผ์ •์„ ์™„๋ฃŒํ•˜๊ธฐ ์ „๊นŒ์ง€ ๋ฉˆ์ถ”์ง€ ์•Š๋Š”๋‹ค.
    • ๋”ฐ๋ผ์„œ ์ปดํฌ๋„ŒํŠธ ์ค‘ ์–ด๋Š ํ•˜๋‚˜๋ผ๋„ ์ƒํ˜ธ ์ž‘์šฉ์ด ๊ฐ€๋Šฅํ•ด์ง€๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ์— ๋Œ€ํ•œ Hydration์ด ์™„๋ฃŒ๋˜์–ด์•ผ ํ•œ๋‹ค.
  • ํ•œ ๋ฒˆ Hydration์ด ์‹œ์ž‘๋˜๋ฉด, ์ „์ฒด tree์— ๋Œ€ํ•ด Hydration์ด ์™„๋ฃŒ๋˜๊ธฐ ์ „๊นŒ์ง€ ์‚ฌ์šฉ์ž๋Š” ๋‹ค๋ฅธ ๋ชจ๋“  ๊ธฐ๋Šฅ(Nav Bar, Side Bar, ...)๊ณผ๋„ ์ƒํ˜ธ์ž‘์šฉํ•  ์ˆ˜ ์—†๋‹ค.
    • Nav Bar์˜ ๊ฒฝ์šฐ ํŽ˜์ด์ง€ ์ž์ฒด์˜ ์ด๋™์— ํ•„์š”ํ•œ ๊ธฐ๋Šฅ์ธ๋ฐ Hydration์ด ์ง„ํ–‰ ์ค‘์ด์–ด์„œ ๋– ๋‚˜๊ณ  ์‹ถ์€ ํŽ˜์ด์ง€์— ๊ณ„์† ๋‚จ์•„์žˆ์–ด์•ผ ํ•˜๊ณ , ์ด๋Š” UX์— ์ข‹์ง€ ์•Š๋‹ค.

๐Ÿง ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์„๊นŒ์š”?

  • ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ์ด์œ ๋Š” ๋ชจ๋“  ๋‹จ๊ณ„๊ฐ€ ์—ฐ๊ฒฐ๋˜์–ด ์ง„ํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
    • ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ(์„œ๋ฒ„) โžก๏ธ HTML๋กœ ๋ Œ๋”๋ง(์„œ๋ฒ„) โžก๏ธ ์ฝ”๋“œ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ(ํด๋ผ์ด์–ธํŠธ) โžก๏ธ Hydration(ํด๋ผ์ด์–ธํŠธ)
    • ๋ชจ๋“  ๊ณผ์ •์—์„œ ์ด์ „ ๋‹จ๊ณ„๊ฐ€ ๋๋‚  ๋•Œ๊นŒ์ง€ ์ „์ฒด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์—†๋‹ค.
  • ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ž‘์—…์„ ๋ถ„ํ• ํ•˜์—ฌ ์ „์ฒด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์•„๋‹Œ ๊ฐ๊ฐ์˜ ๋ถ€๋ถ„๋“ค์— ๋Œ€ํ•œ ์ž‘์—… ์ˆ˜ํ–‰์ด ๊ฐ€๋Šฅํ•ด์ ธ์•ผ ํ•œ๋‹ค.
๐Ÿ“ข React 18์—์„œ๋Š” ์ด๋ ‡๊ฒŒ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค!

๐Ÿค  React 18: Streaming HTML && Selective Hydration

  • React18์—์„œ๋Š” suspense๋ฅผ ์‚ฌ์šฉํ•ด ๋‘ ๊ฐœ์˜ ์ฃผ์š” SSR ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ–ˆ๋‹ค.
  1. Streaming HTML
  • ์„œ๋ฒ„์—์„œ HTML ํŒŒ์ผ์„ ์ŠคํŠธ๋ฆฌ๋ฐ์˜ ํ˜•์‹์œผ๋กœ ์ „๋‹ฌํ•œ๋‹ค.
  • renderToString โžก๏ธ renderToPipeableStream
  • ๊ด€๋ จ PR
  1. Selective Hydration
  • ํด๋ผ์ด์–ธํŠธ์—์„œ ์„ ํƒ์ ์œผ๋กœ Hydration์„ ์ง„ํ–‰ํ•œ๋‹ค.
  • ์ด๋ฅผ ์œ„ํ•ด Client-Side์—์„œ createRoot๋กœ ๋ฐ”๊พผ ๋’ค ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ถ€๋ถ„๋ถ€๋ถ„์„ Suspense๋กœ ๊ฐ์‹ธ์ฃผ์–ด์•ผ ํ•œ๋‹ค.
  • ๊ด€๋ จ PR

๐ŸŒŸ ๋ณด์—ฌ์ฃผ๊ธฐ ์ „์— ์„œ๋ฒ„์—์„œ ๋‹ค ๊ฐ€์ ธ์™€์•ผ ํ•˜๋Š” ๋ฌธ์ œ ํ•ด๊ฒฐ!

<Layout>
  <NavBar />
  <Sidebar />
  <RightPane>
    <Post />
    <Suspense fallback={<Spinner />}>
      <Comments />
    </Suspense>
  </RightPane>
</Layout>
  • ๋Œ“๊ธ€ ๋ถ€๋ถ„์„ Suspense๋กœ ๊ฐ์‹ธ๊ณ , React๋กœ ํ•˜์—ฌ๊ธˆ ์ค€๋น„๋˜๊ธฐ ์ „๊นŒ์ง€ placeholder์— ํ•ด๋‹นํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค.
  • ์ด๋ฅผ ํ†ตํ•ด ๋Œ“๊ธ€ ๋ถ€๋ถ„์˜ data fetching์„ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ณ  ๋‚˜๋จธ์ง€ ํŽ˜์ด์ง€์— ๋Œ€ํ•œ HTML์„ ์ŠคํŠธ๋ฆฌ๋ฐํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์ตœ์ดˆ์˜ HTML์—์„œ๋Š” ๋Œ“๊ธ€ ๊ด€๋ จ ์ปดํฌ๋„ŒํŠธ์— ๋Œ€ํ•œ ์ฝ”๋“œ๊ฐ€ ์‚ฌ๋ผ์ง„๋‹ค.
<div hidden id="comments">
  <!-- Comments -->
  <p>First comment</p>
  <p>Second comment</p>
</div>
<script>
  document
    .getElementById("sections-spinner")
    .replaceChildren(document.getElementById("comments"));
</script>
  • ์„œ๋ฒ„ ์ธก์—์„œ ๋Œ“๊ธ€์— ํ•ด๋‹น๋˜๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ์ค€๋น„๋˜๋ฉด, React์—์„œ๋Š” ๋™์ผํ•œ ์ŠคํŠธ๋ฆผ์— ์ถ”๊ฐ€๋˜๋Š” HTML๊ณผ ์˜ฌ๋ฐ”๋ฅธ ์žฅ์†Œ์— HTML์„ ์œ„์น˜์‹œํ‚ค๊ธฐ ์œ„ํ•œ ์ธ๋ผ์ธ script ํƒœ๊ทธ๋ฅผ ์ „์†กํ•œ๋‹ค.
  • ํด๋ผ์ด์–ธํŠธ์—์„œ React ์ž์ฒด๊ฐ€ ๋ถˆ๋Ÿฌ์™€์ง€๊ธฐ๋„ ์ „์— ๋Šฆ๊ฒŒ ๋„์ฐฉํ•œ ๋Œ“๊ธ€ ๋ถ€๋ถ„์˜ HTML์ด ์‚ฝ์ž…๋œ๋‹ค.
  • ์ด๋ฅผ ํ†ตํ•ด ํ™”๋ฉด ์ผ๋ถ€๋ถ„์— ๋Œ€ํ•œ SSR์„ ํฌ๊ธฐํ•˜์ง€ ์•Š๊ณ ๋„ ํ™”๋ฉด์˜ ์ผ๋ถ€๋ถ„๋งŒ ์„ ํƒํ•˜์—ฌ HTML ์ŠคํŠธ๋ฆฌ๋ฐ ์ƒ์— ๋‚˜์ค‘์— ๋“ค์–ด์˜ค๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋˜ํ•œ ์ด ๋•๋ถ„์— tree ์ƒ์—์„œ ๋” ๋จผ ๊ณณ์— ์œ„์น˜ํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ์˜ ๋ Œ๋”๋ง์ด ์ด๋ฏธ ๋ฐ์ดํ„ฐ๊ฐ€ ์ „์†ก๋œ ๋‹ค์Œ์—๋„ ์ด๋ฃจ์–ด์งˆ ์ˆ˜ ์žˆ๋‹ค.
    • ๋”ฐ๋ผ์„œ ์ „ํ†ต์ ์ธ HTML ์ŠคํŠธ๋ฆฌ๋ฐ ๋ฐฉ์‹๊ณผ ๋‹ฌ๋ฆฌ ์œ„์—์„œ ์•„๋ž˜๋กœ ๋‚ด๋ ค๊ฐ€๋Š” ์ˆœ์„œ๋ฅผ ์ง€ํ‚ฌ ํ•„์š”๋„ ์—†๋‹ค.

๐ŸŒŸ Hydration์„ ์œ„ํ•ด์„œ๋Š” ๋ชจ๋‘ ๋ถˆ๋Ÿฌ์™€์•ผ ํ•˜๋Š” ๋ฌธ์ œ ํ•ด๊ฒฐ!

import { lazy } from "react";

const Comments = lazy(() => import("./Comments.js"));

// ...

<Suspense fallback={<Spinner />}>
  <Comments />
</Suspense>;
  • ๋Œ“๊ธ€์„ ์œ„ํ•œ ์ฝ”๋“œ๊ฐ€ ๋กœ๋”ฉ๋˜๊ธฐ ์ „ ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ Hydration ํ•  ์ˆ˜ ์—†๋Š” ๋ฌธ์ œ๋Š” Code Splitting์„ ํ†ตํ•ด ํ•ด๊ฒฐํ•˜์˜€๋‹ค.
  • ํŠน์ • ์ฝ”๋“œ ๋ถ€๋ถ„์ด ๋™๊ธฐ์ ์œผ๋กœ ๋กœ๋“œ๋  ํ•„์š”๊ฐ€ ์—†์Œ์„ ๋ช…์‹œํ•ด์คŒ์œผ๋กœ์จ ํฐ ๋ฒˆ๋“ค ์‚ฌ์ด์ฆˆ๋ฅผ ํ”ผํ•  ์ˆ˜ ์žˆ๋‹ค.
    • lazy๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฉ”์ธ ๋ฒˆ๋“ค์—์„œ ๋ถ„๋ฆฌ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.
    • ๋ฒˆ๋“ค๋Ÿฌ๋Š” ์ด๋ฅผ ๋ณ„๋„์˜ script ํƒœ๊ทธ๋กœ ๋ถ„๋ฆฌํ•ด์ค€๋‹ค.
  • ์ด๋ฅผ ํ†ตํ•ด ์œ„์˜ ์˜ˆ์‹œ์—์„œ ๋Œ“๊ธ€์— ๋Œ€ํ•œ UI๊ฐ€ ์•„์ง ๋ณด์ด์ง€ ์•Š๋”๋ผ๋„ ๋‹ค๋ฅธ ๋ถ€๋ถ„์˜ ์ด๋ฒคํŠธ๋ฅผ ๋จผ์ € ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

๐ŸŒŸ ์ƒํ˜ธ์ž‘์šฉ์„ ํ•˜๊ธฐ ์ „ ๋ชจ๋‘ Hydration์„ ํ•ด์•ผ ํ•˜๋Š” ๋ฌธ์ œ ํ•ด๊ฒฐ!

<Layout>
  <NavBar />
  <Suspense fallback={<Spinner />}>
    <Sidebar />
  </Suspense>
  <RightPane>
    <Post />
    <Suspense fallback={<Spinner />}>
      <Comments />
    </Suspense>
  </RightPane>
</Layout>
  • ์œ„์˜ ์ฝ”๋“œ์—์„œ NavBar์™€ Post๋งŒ Hydration์ด ์™„๋ฃŒ ๋˜๊ณ , SideBar์™€ Comments ์ปดํฌ๋„ŒํŠธ๋Š” HTML ์ŠคํŠธ๋ฆฌ๋ฐ๋งŒ ์™„๋ฃŒ๋œ ์ƒํƒœ๋ผ๊ณ  ํ•˜์ž.
    • SideBar์™€ Comments ์ฝ”๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๋ฒˆ๋“ค์ด ๋ถˆ๋Ÿฌ์™€์ง€๊ณ , React๋Š” tree ์ƒ์—์„œ ๋จผ์ € ๋ฐœ๊ฒฌ๋˜๋Š” ์ปดํฌ๋„ŒํŠธ์ธ SideBar์— ๋Œ€ํ•œ Hydration์„ ๋จผ์ € ์ง„ํ–‰ํ•˜๊ฒŒ ๋œ๋‹ค.
    • ๋งŒ์•ฝ ์ด๋•Œ ์‚ฌ์šฉ์ž๊ฐ€ ๋Œ“๊ธ€ ๋ถ€๋ถ„์„ ํด๋ฆญํ•  ๊ฒฝ์šฐ, React๋Š” ํ•ด๋‹น ํด๋ฆญ์„ ๊ธฐ๋กํ•ด๋‘์—ˆ๋‹ค๊ฐ€ Comments ์ปดํฌ๋„ŒํŠธ์— ๋Œ€ํ•œ Hydration์— ์šฐ์„ ์ˆœ์œ„๋ฅผ ๋ถ€์—ฌํ•œ๋‹ค.
    • React๋Š” ์ด์ œ ์›๋ž˜ ์ˆ˜ํ–‰ํ•˜๋ ค ํ–ˆ๋˜ SideBar์— ๋Œ€ํ•œ Hydration ๋Œ€์‹  Comments ์ปดํฌ๋„ŒํŠธ์— ๋Œ€ํ•œ Hydration์„ ๋จผ์ € ์ง„ํ–‰ํ•œ๋‹ค.
  • ์ด๋ฅผ ํ†ตํ•ด React๋Š” ์ตœ๋Œ€ํ•œ ๋น ๋ฅด๊ฒŒ ๋ชจ๋“  ๊ฒƒ์— ๋Œ€ํ•œ Hydration์„ ์™„๋ฃŒํ•˜๋ฉด์„œ๋„ ์‚ฌ์šฉ์ž์˜ ๋™์ž‘์— ๊ธฐ๋ฐ˜ํ•ด ํ™”๋ฉด ์ƒ์—์„œ ๊ฐ€์žฅ ๊ธ‰ํ•œ ๋ถ€๋ถ„์— ์šฐ์„  ์ˆœ์œ„๋ฅผ ๋ถ€์—ฌํ•œ๋‹ค.
์šฐ๋ฆฌ๋Š” ์ด์ œ ์„œ๋ฒ„ ์ƒ์—์„œ HTML์„ ๋ณด๋‚ด๊ธฐ ์ „ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๊ฐ€ ๋ถˆ๋Ÿฌ์™€์ง€๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค.
๋˜ํ•œ Hydration์„ ์‹œ์ž‘ํ•˜๊ธฐ ์ „ ๋ชจ๋“  JS ์ฝ”๋“œ๊ฐ€ ๋ถˆ๋Ÿฌ์™€์ง€๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š์•„๋„ ๋˜๊ณ ,
ํŽ˜์ด์ง€ ์ƒ์˜ ์ƒํ˜ธ ์ž‘์šฉ์„ ์œ„ํ•ด ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ์— ๋Œ€ํ•œ Hydration์ด ์™„๋ฃŒ๋˜๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š์•„๋„ ๋œ๋‹ค!

๐Ÿ”Ž References

์ฐธ๊ณ  ์ž๋ฃŒ ๋ชจ์Œ
profile
An investment in knowledge pays the best interest๐Ÿ™ƒ
post-custom-banner

3๊ฐœ์˜ ๋Œ“๊ธ€

comment-user-thumbnail
2024๋…„ 4์›” 21์ผ

Hydration์„ ์ž˜ ์„ค๋ช…ํ•œ ๊ธ€ ๊ฐ™์•„์š”! ๋งŽ์€ ๋„์›€ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2024๋…„ 9์›” 28์ผ

ํ•ต์‹ฌ์„ ๋„ˆ๋ฌด ์ž˜ ์ •๋ฆฌํ•ด์ฃผ์…”์„œ ๋งŽ์€ ๋„์›€ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค ๐Ÿ‘๐Ÿป

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ