React ๊ณต์‹๋ฌธ์„œ!!

๋“ค์–ด๊ฐ€๋ฉฐ

์ตœ๊ทผ Allini ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋ฉด์„œ ๋ช‡ ๊ฐ€์ง€ ๊ณ ๋ฏผ์ด ์ƒ๊ฒผ์Šต๋‹ˆ๋‹ค.

over-fetching, waterfall ํ˜„์ƒ์œผ๋กœ ์ธํ•œ ์„ฑ๋Šฅ ์ €ํ•˜, ๊ทธ๋ฆฌ๊ณ  ๋ฌด์—‡๋ณด๋‹ค ๋น ๋ฅธ ์‹œ์žฅ ๊ฒ€์ฆ์„ ์œ„ํ•ด ๋‹ค์–‘ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํ™œ์šฉํ•ด์•ผ ํ•˜๋Š” ์ƒํ™ฉ์—์„œ ๋ฐœ์ƒํ•˜๋Š” ๋ฒˆ๋“ค ์‚ฌ์ด์ฆˆ ์ฆ๊ฐ€ ๋ฌธ์ œ์˜€์ฃ .

 

์ข‹์€ ๊ฐœ๋ฐœ์ž๋Š” ๋‹จ์ˆœํžˆ ๋ชจ๋“  ๊ฒƒ์„ ์†์ˆ˜ ์ฒ˜์Œ๋ถ€ํ„ฐ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ์ ์ ˆํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ ํƒํ•˜๊ณ  ์กฐ์žกํ•ด ๋น ๋ฅด๊ฒŒ ์ œํ’ˆ์„ ๋งŒ๋“ค์–ด๋‚ด๋Š” ๋Šฅ๋ ฅ์ด ์ค‘์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

 

ํ•˜์ง€๋งŒ ์ด๋Ÿฌํ•œ ์ ‘๊ทผ์€ ํ•„์—ฐ์ ์œผ๋กœ ๋ฒˆ๋“ค ์‚ฌ์ด์ฆˆ ์ฆ๊ฐ€๋ผ๋Š” ๋ฌธ์ œ๋ฅผ ๋™๋ฐ˜ํ•˜๊ฒŒ ๋˜์—ˆ๊ณ , ์ด๋Š” ์ œ๊ฐ€ React ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ์— ๊ด€์‹ฌ์„ ๊ฐ–๊ฒŒ ๋œ ์ฃผ๋œ ๊ณ„๊ธฐ๊ฐ€ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!

 

1. React ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ์˜ ํ˜„์žฌ ์‚ฌ์šฉ ๊ฐ€๋Šฅ ์—ฌ๋ถ€

ํ˜„์žฌ ์ƒํƒœ

  • React 18 ๋ฒ„์ „: ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ ๋ฏธ์ง€์›
  • React 19 RC(Release Candidate): ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ ์ง€์›
 

ํ•˜์ง€๋งŒ ํ˜„์žฌ React 18.2.0์„ ์‚ฌ์šฉ์ค‘์ธ ํ”„๋กœ์ ํŠธ์—์„œ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•˜๊ธฐ๋Š” ์–ด๋ ต์Šต๋‹ˆ๋‹ค.

React 19๋กœ์˜ ์—…๊ทธ๋ ˆ์ด๋“œ๋ฅผ ๊ณ ๋ คํ•ด๋ณผ ์ˆ˜ ์žˆ์ง€๋งŒ, RC ๋ฒ„์ „์ด๊ธฐ ๋•Œ๋ฌธ์— ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ์˜ ์‚ฌ์šฉ์€ ์‹ ์ค‘ํžˆ ๊ฒฐ์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

2. SSR๊ณผ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ์˜ ๊ด€๊ณ„

ํ•™์Šต ์ดˆ๊ธฐ์— ๊ฐ€์žฅ ํ—ท๊ฐˆ๋ ธ๋˜ ๊ฐœ๋…์ž…๋‹ˆ๋‹ค!

SSR (Server-Side Rendering)

  • ๋ชฉ์ : ์ดˆ๊ธฐ ํŽ˜์ด์ง€ ๋กœ๋“œ ์„ฑ๋Šฅ ๊ฐœ์„  ๋ฐ SEO ์ตœ์ ํ™”
  • ๋™์ž‘ ๋ฐฉ์‹:
    • ์„œ๋ฒ„์—์„œ ์ „์ฒด ํŽ˜์ด์ง€์˜ ์ดˆ๊ธฐ HTML์„ ์ƒ์„ฑ
    • ํด๋ผ์ด์–ธํŠธ๋กœ HTML๊ณผ JS ๋ฒˆ๋“ค์„ ์ „์†ก
    • ํด๋ผ์ด์–ธํŠธ์—์„œ hydration ๊ณผ์ •์„ ํ†ตํ•ด ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒํ•œ ์•ฑ์œผ๋กœ ์ „ํ™˜

์ด์ „ React ๊ณต์‹ ๋ฌธ์„œ์— ๋”ฐ๋ฅด๋ฉด, React์˜ ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง ๋ฉ”์„œ๋“œ๋“ค์€ ํฌ๊ฒŒ ์„ธ ๊ฐ€์ง€ ํ™˜๊ฒฝ์œผ๋กœ ๊ตฌ๋ถ„๋ฉ๋‹ˆ๋‹ค:

 

Node.js Streams ํ™˜๊ฒฝ์šฉ:

  • renderToPipeableStream()
  • renderToNodeStream() (Deprecated)
  • renderToStaticNodeStream()

Web Streams ํ™˜๊ฒฝ์šฉ (๋ธŒ๋ผ์šฐ์ €, Deno, modern edge runtimes):

  • renderToReadableStream()

์ŠคํŠธ๋ฆผ์„ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ํ™˜๊ฒฝ์šฉ:

  • renderToString()
  • renderToStaticMarkup()

๊ธฐ์กด SSR์˜ ๋™์ž‘ ๋ฐฉ์‹์€ ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

// ๊ธฐ์กด SSR์˜ ๋™์ž‘ ๋ฐฉ์‹
// 1. ์„œ๋ฒ„์—์„œ ์ดˆ๊ธฐ ๋ Œ๋”๋ง
const app = ReactDOMServer.renderToPipeableStream(<App />);
// ํ•œ๋ฒˆ์— ์ „์ฒด HTML์„ ์ƒ์„ฑํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ๋กœ ์ „์†ก

// 2. HTML ๋ฌธ์„œ์— ์‚ฝ์ž…
const html = `
  <!doctype html>
  <html>
    <body>
      <div id="root">${app}</div>
      <script src="/bundle.js"></script>
    </body>
  </html>
`;

 

 

๊ณต์‹ ๋ฌธ์„œ์— ๋”ฐ๋ฅด๋ฉด, renderToPipeableStream์„ ํ†ตํ•ด ์ดˆ๊ธฐ ์…ธ(shell)์„ ๋ Œ๋”๋งํ•˜๊ณ  ์ „์†กํ•ฉ๋‹ˆ๋‹ค.

renderToPipeableStream์˜ ๊ธฐ๋ณธ ๊ฐœ๋…์€ ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • Node.js ํ™˜๊ฒฝ์—์„œ React ํŠธ๋ฆฌ๋ฅผ HTML ์ŠคํŠธ๋ฆผ์œผ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” API์ž…๋‹ˆ๋‹ค.
  • ์ ์ง„์ ์ธ ๋กœ๋”ฉ์ด ๊ฐ€๋Šฅํ•œ ์ŠคํŠธ๋ฆฌ๋ฐ SSR์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ์‹œ ์ฝ”๋“œ

// ๋ฐœ์ „๋œ SSR (์ŠคํŠธ๋ฆฌ๋ฐ ๋ฐฉ์‹)
const { pipe } = renderToPipeableStream(<App />, {
  bootstrapScripts: ['/main.js'],
  onShellReady() {
    // 1. ๋จผ์ € ๊ธฐ๋ณธ ๋ผˆ๋Œ€(shell)๋ฅผ ๋ณด๋ƒ„
    // ์ดˆ๊ธฐ shell(Suspense ๊ฒฝ๊ณ„ ์œ„์˜ ์ฝ˜ํ…์ธ )์ด ์ค€๋น„๋˜๋ฉด ์ŠคํŠธ๋ฆฌ๋ฐ ์‹œ์ž‘

    pipe(response);
  },
  onAllReady() {
    // ๋ชจ๋“  ์ฝ˜ํ…์ธ ๊ฐ€ ์ค€๋น„๋˜๋ฉด ํ˜ธ์ถœ (ํฌ๋กค๋Ÿฌ๋‚˜ ์ •์  ์ƒ์„ฑ์šฉ)
  }
});

 

๊ธฐ์กด์˜ renderToString์€ ์ œํ•œ์ ์ธ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š” ๋ฐ˜๋ฉด, renderToPipeableStream์€ Suspense๋ฅผ ์™„์ „ํžˆ ์ง€์›ํ•˜๊ณ  HTML ์ŠคํŠธ๋ฆฌ๋ฐ์ด ๊ฐ€๋Šฅํ•œ ๋” ๋ฐœ์ „๋œ ํ˜•ํƒœ์˜ SSR ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

 

์ฃผ์š” ์ฐจ์ด์ :

  • ๊ธฐ์กด SSR: ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค ๋ชจ์•„์„œ ํ•œ๋ฒˆ์— ๋ณด๋ƒ„ (๋А๋ฆผ)
  • ์ƒˆ๋กœ์šด SSR:
    1. ๋จผ์ € ํŽ˜์ด์ง€์˜ ๊ธฐ๋ณธ ๋ผˆ๋Œ€๋ฅผ ๋ณด๋‚ด๊ณ 
    2. ๋‚˜๋จธ์ง€ ๋‚ด์šฉ์€ ์ค€๋น„๋˜๋Š” ๋Œ€๋กœ ์กฐ๊ธˆ์”ฉ ๋ณด๋ƒ„ (๋” ๋น ๋ฆ„)

 

์‰ฝ๊ฒŒ ๋งํ•˜๋ฉด, ๊ธฐ์กด SSR์€ "์‹๋‹น์—์„œ ๋ชจ๋“  ์š”๋ฆฌ๊ฐ€ ์™„์„ฑ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ ธ๋‹ค๊ฐ€ ํ•œ๋ฒˆ์— ์„œ๋น™"ํ•˜๋Š” ๊ฒƒ์ด๊ณ , ์ƒˆ๋กœ์šด ๋ฐฉ์‹์€ "์ค€๋น„๋œ ๋ฉ”๋‰ด๋ถ€ํ„ฐ ๋จผ์ € ์„œ๋น™ํ•˜๊ณ , ๋‚˜๋จธ์ง€๋Š” ์™„์„ฑ๋˜๋Š” ๋Œ€๋กœ ๊ฐ€์ ธ๋‹ค์ฃผ๋Š”" ๊ฒƒ๊ณผ ๋น„์Šทํ•ฉ๋‹ˆ๋‹ค.

 

React ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ (RSC)

  • ๋ชฉ์ : ๋ฒˆ๋“ค ์‚ฌ์ด์ฆˆ ์ตœ์ ํ™” ๋ฐ ์„œ๋ฒ„ ๋ฆฌ์†Œ์Šค ์ง์ ‘ ์ ‘๊ทผ
  • ๋™์ž‘ ๋ฐฉ์‹:
    • ํŠน์ • ์ปดํฌ๋„ŒํŠธ๋ฅผ ์„œ๋ฒ„์—์„œ๋งŒ ์‹คํ–‰๋˜๋„๋ก ์ง€์ •
    • ์„œ๋ฒ„์—์„œ ๋ Œ๋”๋ง๋œ ๊ฒฐ๊ณผ๋งŒ ํด๋ผ์ด์–ธํŠธ๋กœ ์ „์†ก
    • JS ๋ฒˆ๋“ค์— ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ ์ฝ”๋“œ๋Š” ๋ฏธํฌํ•จ

๋‘ ๊ธฐ์ˆ ์˜ ์ƒํ˜ธ๋ณด์™„์  ๊ด€๊ณ„

SSR๊ณผ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋Š” ์„œ๋กœ๋ฅผ ๋Œ€์ฒดํ•˜๋Š” ๊ธฐ์ˆ ์ด ์•„๋‹Œ, ๋ณด์™„ํ•˜๋Š” ๊ธฐ์ˆ ์ž…๋‹ˆ๋‹ค:

  1. ์—ญํ•  ๋ถ„๋‹ด
    • SSR: ์ดˆ๊ธฐ ํŽ˜์ด์ง€ ๋กœ๋“œ ์‹œ ์ „์ฒด HTML ์ƒ์„ฑ
    • ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ: ํŠน์ • ์ปดํฌ๋„ŒํŠธ๋“ค์˜ ์„œ๋ฒ„ ์‹คํ–‰ ๋ฐ ๋ฒˆ๋“ค ํฌ๊ธฐ ์ตœ์ ํ™”

 

3. ํ”„๋ ˆ์ž„์›Œํฌ๋“ค์˜ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ ๊ตฌํ˜„

Next.js์˜ ์ ‘๊ทผ

Next.js๋Š” ์ž์ฒด์ ์ธ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ ๊ตฌํ˜„์„ ํ†ตํ•ด React์˜ ์‹คํ—˜์  ๊ธฐ๋Šฅ์„ ์•ˆ์ •์ ์œผ๋กœ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

  1. React ์ฝ”์–ด ํŒ€๊ณผ Next.js ํŒ€์˜ ํ˜‘๋ ฅ
    • React ์ฝ”์–ด ํŒ€์˜ ์ฃผ์š” ๋ฉค๋ฒ„๋“ค(Joe Savona, Sebastian Markbåge ๋“ฑ)์ด Vercel(Next.js)์— ํ•ฉ๋ฅ˜
    • ์ด๋ฅผ ํ†ตํ•ด React์˜ ์‹คํ—˜์  ๊ธฐ๋Šฅ์„ Next.js์—์„œ ๋จผ์ € ์•ˆ์ •์ ์œผ๋กœ ๊ตฌํ˜„ ๊ฐ€๋Šฅ
  2. ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ์˜ ๋ฐœ์ „ ๊ณผ์ •
    • 2020๋…„: React ํŒ€์ด ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ ๊ฐœ๋… ์ฒซ ๋ฐœํ‘œ
    • React 18: ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ ๊ธฐ์ดˆ ์ธํ”„๋ผ ํฌํ•จ, but ์™„์ „ํ•œ ๊ตฌํ˜„์€ ์•„๋‹˜
    • Next.js 13: App Router์™€ ํ•จ๊ป˜ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ ์ „๋ฉด ๋„์ž…

๊ธฐ์ˆ ์  ๊ตฌํ˜„ ๋ฐฉ์‹

React์˜ Server Components์— ๋Œ€ํ•œ ๊ณต์‹๋ฌธ์„œ๋ฅผ ๋ณด๋ฉด,

๋ฌธ์„œ์—์„œ๋Š” Server Components ๊ตฌํ˜„์— ๋Œ€ํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์–ธ๊ธ‰ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค:

"To support React Server Components as a bundler or framework, we recommend pinning to a specific React version, or using the Canary release. We will continue working with bundlers and frameworks to stabilize the APIs used to implement React Server Components in the future."

์ด๋Š” Server Components ๊ตฌํ˜„์„ ์œ„ํ•œ ๋ฒˆ๋“ค๋Ÿฌ API๊ฐ€ ์•„์ง ์™„์ „ํžˆ ์•ˆ์ •ํ™”๋˜์ง€ ์•Š์•˜์Œ์„ ์‹œ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

 

Next.js๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค:

// next.config.js
{
  webpack: (config, { isServer }) => {
    if (isServer) {
      // ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ ์ฒ˜๋ฆฌ
      config.plugins.push(new webpack.DefinePlugin({
        // marked, sanitize-html ๊ฐ™์€ ์„œ๋ฒ„ ์ „์šฉ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์ด
        // ํด๋ผ์ด์–ธํŠธ ๋ฒˆ๋“ค์— ํฌํ•จ๋˜์ง€ ์•Š๋„๋ก ์ฒ˜๋ฆฌ
        'process.env.SERVER_ONLY': JSON.stringify(true)
      }));
      
      config.module.rules.push({
        test: /\.(js|jsx|ts|tsx)$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-react'],
            plugins: [
              // async ์ปดํฌ๋„ŒํŠธ ์ง€์›์„ ์œ„ํ•œ ๋ณ€ํ™˜
              '@babel/plugin-syntax-top-level-await',
              // Server Component์˜ import ๊ตฌ๋ฌธ ์ฒ˜๋ฆฌ
              ['@babel/plugin-transform-modules-commonjs', {
                importInterop: 'node'
              }]
            ]
          }
        }
      });
    } else {
      // ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ ์ฒ˜๋ฆฌ
      config.module.rules.push({
        test: /\.(js|jsx|ts|tsx)$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-react'],
            plugins: [
              // "use client" ์ง€์‹œ์–ด๊ฐ€ ์žˆ๋Š” ํŒŒ์ผ๋งŒ ํด๋ผ์ด์–ธํŠธ ๋ฒˆ๋“ค์— ํฌํ•จ
              ['./plugins/client-directive', {}],
              // Server Component์˜ ์ถœ๋ ฅ์„ ํด๋ผ์ด์–ธํŠธ์—์„œ hydrateํ•˜๊ธฐ ์œ„ํ•œ ๋ณ€ํ™˜
              ['./plugins/server-reference', {}]
            ]
          }
        }
      });
    }
    return config;
  }
}

// Server Component ๋ Œ๋”๋ง ํ•จ์ˆ˜
async function renderServerComponent(Component, props) {
  // ๋ฌธ์„œ์— ์–ธ๊ธ‰๋œ ๊ฒƒ์ฒ˜๋Ÿผ build time ๋˜๋Š” request time์— ์‹คํ–‰ ๊ฐ€๋Šฅ
  const stream = await ReactServerDOM.renderToReadableStream(
    <Component {...props} />,
    // ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ์˜ ๋ฒˆ๋“ค ์ •๋ณด๋ฅผ ๋‹ด์€ ๋งคํ•‘
    webpackMap
  );
  
  // React์˜ Flight ํฌ๋งท์œผ๋กœ ์ง๋ ฌํ™”
  return encodeRSCPayload(stream);
}

 

์ด ๊ตฌํ˜„์€ ๊ณต์‹ ๋ฌธ์„œ์˜ ๋‹ค์Œ ๊ฐœ๋…๋“ค์„ ๋ฐ˜์˜ํ•ฉ๋‹ˆ๋‹ค:

  1. "Server Components are a new type of Component that renders ahead of time, before bundling, in an environment separate from your client app or SSR server."
    • webpack ์„ค์ •์—์„œ isServer ํ”Œ๋ž˜๊ทธ๋กœ ํ™˜๊ฒฝ์„ ๋ถ„๋ฆฌ
  2. "Server Components can run once at build time on your CI server, or they can be run for each request using a web server."
    • renderServerComponent ํ•จ์ˆ˜๊ฐ€ ์ด ๋‘ ๊ฐ€์ง€ ์ผ€์ด์Šค๋ฅผ ๋ชจ๋‘ ์ง€์›
  3. "Async Components are a new feature of Server Components that allow you to await in render."
    • ์„œ๋ฒ„ ์ธก babel ์„ค์ •์— @babel/plugin-syntax-top-level-await ํฌํ•จ

ํ•ต์‹ฌ ๊ตฌํ˜„ ์š”์†Œ

  1. RSC ํฌ๋งท
    • ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ์˜ ๋ Œ๋”๋ง ๊ฒฐ๊ณผ๋ฅผ ํŠน๋ณ„ํ•œ ํฌ๋งท์œผ๋กœ ์ง๋ ฌํ™”
    • JSON์ด ์•„๋‹Œ ํŠน๋ณ„ํ•œ ๋ฐ”์ด๋„ˆ๋ฆฌ ํ˜•์‹ ์‚ฌ์šฉ
    • React Flight ์•„ํ‚คํ…์ฒ˜ ํ™œ์šฉ
  2. ๋ฒˆ๋“ค๋ง ์ตœ์ ํ™”
    • ์„œ๋ฒ„ ์ „์šฉ ์ฝ”๋“œ๋ฅผ ํด๋ผ์ด์–ธํŠธ ๋ฒˆ๋“ค์—์„œ ์ œ์™ธ
    • ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋งŒ ์„ ํƒ์ ์œผ๋กœ ๋ฒˆ๋“ค๋ง
  3. ์ŠคํŠธ๋ฆฌ๋ฐ ์ง€์›
    • React Suspense์™€ ํ†ตํ•ฉ
    • ์ ์ง„์ ์ธ ํŽ˜์ด์ง€ ๋กœ๋”ฉ ๊ตฌํ˜„

์ดํ•ด๋ฅผ ์œ„ํ•ด ๊ธฐ๋ณธ์ ์ธ ํ‹€์— ๋งž์ถฐ ๊ฐ„์†Œํ™”ํ•ด ๊ตฌํ˜„ํ•ด ๋ดค์Šต๋‹ˆ๋‹ค!
ํ˜น์‹œ ํ‹€๋ฆฐ ๋ถ€๋ถ„์ด ์žˆ๋‹ค๋ฉด ํŽธํ•˜๊ฒŒ ๋Œ“๊ธ€ ์ฃผ์‹œ๋ฉด ๊ฐ์‚ฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค!

Remix์˜ ์ ‘๊ทผ

Remix๋Š” ๋ผ์šฐํ„ฐ ๊ธฐ๋ฐ˜์˜ ์„œ๋ฒ„ ์ค‘์‹ฌ ์•„ํ‚คํ…์ฒ˜๋ฅผ ์ฑ„ํƒํ•˜์—ฌ ์œ ์‚ฌํ•œ ์ด์ ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

// Remix์˜ ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋กœ์ง ์˜ˆ์‹œ
export async function loader({ request }) {
  const data = await getProducts();
  return json(data);
}

export default function Products() {
  const products = useLoaderData();
  return (
    <div>
      <h1>Products</h1>
      <ProductList products={products} />
    </div>
  );
}

 

4. Next.js ์•ฑ ๋ผ์šฐํ„ฐ์™€ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ์˜ ๊ด€๊ณ„

Next.js์˜ ์•ฑ ๋ผ์šฐํ„ฐ๋Š” ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์ฑ„ํƒํ–ˆ์Šต๋‹ˆ๋‹ค.  ๋งค์šฐ ์ค‘์š”ํ•œ ์•„ํ‚คํ…์ฒ˜์  ๊ฒฐ์ •์ด์ฃ ?!

๊ธฐ๋ณธ ๊ตฌ์กฐ

// app/layout.jsx (์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ)
export default function RootLayout({ children }) {
  return (
    <html>
      <body>{children}</body>
    </html>
  );
}

// app/page.jsx (์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ)
async function Home() {
  const data = await getData(); // ์„œ๋ฒ„์—์„œ ์ง์ ‘ ๋ฐ์ดํ„ฐ fetch
  
  return (
    <main>
      <h1>Welcome</h1>
      <ClientComponent data={data} />
    </main>
  );
}

// components/client-component.jsx
'use client';

function ClientComponent({ data }) {
  // ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ ์ธํ„ฐ๋ž™์…˜์ด ํ•„์š”ํ•œ ์ปดํฌ๋„ŒํŠธ
  return <div>{/* ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒ UI */}</div>;
}

 

์ฃผ์š” ํŠน์ง•

์ž๋™ ์ฝ”๋“œ ๋ถ„ํ• 

// app/products/page.jsx
import { ProductList } from './components/product-list';

async function ProductsPage() {
  const products = await fetchProducts(); // ์„œ๋ฒ„์—์„œ๋งŒ ์‹คํ–‰
  return <ProductList products={products} />;
}

// ์ด ์ปดํฌ๋„ŒํŠธ์™€ ๊ด€๋ จ๋œ ์„œ๋ฒ„ ๋กœ์ง์€ ํด๋ผ์ด์–ธํŠธ ๋ฒˆ๋“ค์— ํฌํ•จ๋˜์ง€ ์•Š์Œ

 

 

์ŠคํŠธ๋ฆฌ๋ฐ๊ณผ Suspense ํ†ตํ•ฉ

// app/dashboard/page.jsx
import { Suspense } from 'react';

export default function Dashboard() {
  return (
    <div>
      <Suspense fallback={<LoadingUI />}>
        <SlowComponent />
      </Suspense>
    </div>
  );
}
 

๋งˆ์น˜๋ฉฐ

ํ˜„์žฌ ์ œ๊ฐ€ ์ง„ํ–‰ ์ค‘์ธ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” React 18.2.0์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์–ด ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•˜๊ธฐ๋Š” ์–ด๋ ค์šด ์ƒํ™ฉ์ž…๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ๊ณ ๊ฐ ํ”ผ๋“œ๋ฐฑ์„ ๋ฐ›์€ ํ›„ Next.js๋กœ์˜ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์„ ๊ณ ๋ คํ•˜๊ณ  ์žˆ์œผ๋ฉฐ, ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ์˜ ์ด์ ์„ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ข‹์€ ๊ธฐํšŒ๊ฐ€ ๋  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

 

ํ”„๋กœ์ ํŠธ๊ฐ€ ์ปค์ง€๋ฉฐ, ๋ฒˆ๋“ค ์‚ฌ์ด์ฆˆ ์ตœ์ ํ™”์™€ ์„œ๋ฒ„ ๋ฆฌ์†Œ์Šค ํ™œ์šฉ ์ธก๋ฉด์—์„œ ํฐ ์ด์ ์„ ์ œ๊ณตํ•  ๊ฒƒ์œผ๋กœ ๊ธฐ๋Œ€๋ฉ๋‹ˆ๋‹ค!

 

 

 

๐Ÿ“ƒ ์ฐธ๊ณ  ๋ฌธํ—Œ  
React 19 RC!!!
React RFC ๊นƒํ—™
Next.js App Router RFC ๊นƒํ—™
Next.js Server Components ๊ณต์‹๋ฌธ์„œ
React CoreํŒ€ Dan Abramov์˜ Server Components ์†Œ๊ฐœ ๋ฐœํ‘œ
์นด์นด์˜คํŽ˜์ด - React Server Components
์š”์ฆ˜ IT - React Server Components
freeCodeCamp - React Server Components

 

+ Recent posts