๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ’ป DEV/NextJS

[NEXT.js 14] 2. loading.js & Suspense & streamed Response (์„ธ๋ถ„ํ™” ๋กœ๋”ฉ์ƒํƒœ ๊ด€๋ฆฌ)

by Rising Oneโ˜… 2024. 6. 14.
728x90
๋ฐ˜์‘ํ˜•
SMALL

 

loding.js (์ง€์—ฐ)

 

  1. ์ •์˜

 

  2. ์ฐธ๊ณ ์˜ˆ์‹œ

 

  3. ํŒŒ์ผ์˜ ์œ„์น˜

 

  4. suspense & streamed Response๋ฅผ ์ด์šฉํ•œ ์„ธ๋ถ„ํ™” ๋กœ๋”ฉ์ƒํƒœ ๊ด€๋ฆฌ


์ƒ์„ธ

  1. ์ •์˜

: loading.js ํŒŒ์ผ์€  Suspense ๊ธฐ๋ฐ˜์˜ ์ฆ‰๊ฐ์ ์ธ ๋กœ๋”ฉ ์ƒํƒœ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Œ.

- ๊ธฐ๋ณธ์ ์œผ๋กœ Server side ์ด์ง€๋งŒ 'use client'; ๋ฅผ ์ฃผ๋ฉฐ client side ๋กœ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋‹ค.

 

=> Data๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ํŽ˜์ด์ง€์—์„œ ํŽ˜์ด์ง€์˜ ์ƒˆ๋กœ๊ณ ์นจ์„ ํ•  ๋•Œ ์ง€์—ฐ(loading.js)์‹œ๊ฐ„์„ ๋‘๊ฒŒ ๋˜๋ฉด, ํŽ˜์ด์ง€๊ฐ€ ๊นœ๋นก์ด๋ฉฐ ๋‚˜ํƒ€๋‚˜๊ฒŒ ๋œ๋‹ค.
=> ๊ทธ๋Ÿฌ๋‚˜, ์„œ๋กœ ๋‹ค๋ฅธ ํŽ˜์ด์ง€๊ฐ„์˜ ์ด๋™์—์„œ๋Š” ๊นœ๋นก์ž„์—†์ด ํŽ˜์ด์ง€๊ฐ„ ์ „ํ™˜์ด ์ด๋ค„์ง„๋‹ค.
>> โ˜… ๊ทธ ์ด์œ ๋Š”, NEXT๋Š” ์•„์ฃผ ๊ฐ•๋ ฅํ•œ ์บ์‹ฑ์„ ํ•˜๋Š”๋ฐ, ํŽ˜์ด์ง€์— ์ฒซ ์ ‘์† ๋•Œ์— ํ™”๋ฉด๊ตฌ์„ฑ์ด๋ฉฐ ๋ฐ์ดํ„ฐ ๋“ฑ ๋ชจ๋“  ๊ฒƒ์„ ์บ์‹ฑํ•œ๋‹ค.

 


  2. ์ฐธ๊ณ ์˜ˆ์‹œ

// loading.js

export default function Loading() {
  // Or a custom loading skeleton component
  return <p>Loading...</p>
}

 

- ํŒŒ์ผ๋ช…์€ ํŒŒ์ผ๊ทœ์น™์ƒ loading.js ๋กœ ๊ณ ์ •!


 

  3. ํŒŒ์ผ์˜ ์œ„์น˜

case1) project/app/loading.js
=> ๋ชจ๋“  ํŽ˜์ด์ง€์™€ ๋ ˆ์ด์•„์›ƒ์— ์ ์šฉ๋˜์–ด ๋ฒ„๋ฆผ

case2) project/app/ํŠน์ •์ปดํฌ๋„ŒํŠธ/loading.js
=> ํŠน์ • ์ปดํฌ๋„ŒํŠธ ํŽ˜์ด์ง€์™€ ๋ ˆ์ด์•„์›ƒ์—๋งŒ ์ ์šฉ๋จ

 

  4. suspense & streamed Response๋ฅผ ์ด์šฉํ•œ ์„ธ๋ถ„ํ™” ๋กœ๋”ฉ์ƒํƒœ ๊ด€๋ฆฌ

๋ชฉ์  : Data๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ถ€๋ถ„์„ ๋ถ„๋ฆฌ๋œ ์ปดํฌ๋„ŒํŠธ๋กœ ์•„์›ƒ์†Œ์‹ฑ

- 1) ๋ถ„๋ฆฌ์‹œํ‚จ ์ปดํฌ๋„ŒํŠธ๋ฅผ React์— ๋‚ด์žฅ๋œ ์ปดํฌ๋„ŒํŠธ <Suspense>๋กœ ๋ž˜ํ•‘(wrapping) ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

<Suspense> : react ์—์„œ ์ œ๊ณตํ•ด์ฃผ๋Š” ์ปดํฌ๋„ŒํŠธ, ์ผ๋ถ€ ๋ฐ์ดํ„ฐ or ๋ฆฌ์†Œ์Šค๊ฐ€ ๋ถˆ๋ ค์งˆ ๋•Œ๊นŒ์ง€ ๋กœ๋”ฉ ์ƒํƒœ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ  ๋Œ€์ฒด ์ปจํ…์ธ ๋ฅผ ํ‘œ์‹œ.

 

// data ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ƒˆ๋กœ ์ƒ์„ฑํ•ด์ค€๋‹ค
โ—ผ๏ธŽ async function Meals() { // ๊ธฐ๋ณธ์ ์œผ๋กœ server ์ปดํฌ๋„ŒํŠธ์ด๊ธฐ์— async ์‚ฌ์šฉ
โ—ผ๏ธŽ  const meals = await getMeals(); // ๊ทธ๋ฆฌ๊ณ  data๋ฅผ ๋ฐ›์„ ์ค€๋น„

โ—ผ๏ธŽ  return <MealsGrid meals={meals}/> // meals-item์„ grid์— map์œผ๋กœ ๊ทธ๋ฆฌ๊ณ  grid๋ฅผ page์— ํ‘œ์‹œํ• ๊ฑด๋ฐ, ํ˜„์žฌ๋Š” ๋นˆ๋ฐฐ์—ด
โ—ผ๏ธŽ }

==> ์ด๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๊ณ  Promise๋ฅผ ๋ฐ˜ํ™˜ํ•ด์ค€๋‹ค.
==> ์œ„๊ฐ™์€ ์ปดํฌ๋„ŒํŠธ๊ฐ€ suspense๋ฅผ ์ œ๋™ํ•ด์„œ ๋กœ๋”ฉ์ด ๋๋‚  ๋•Œ๊นŒ์ง€ ๋‚˜๋จธ์ง€ ํ™”๋ฉด์„ ๋ณด์—ฌ์ฃผ๊ณ  ํƒœ๊ทธ๋‚ด์— ๋‹ด๊ธด ์ปดํฌ๋„ŒํŠธ(loading ๊ด€๋ จ)๋Š” ๋ณด์—ฌ์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.
==> โ—ผ๏ธŽ ์†์„ฑ : fallback={} ์„ ์ฃผ๋ฉด ๋˜๊ณ , ๊ทธ ์‚ฌ์ด์— ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋„ฃ์–ด์ค€๋‹ค.  

export default async function MealsPage() {

  return (
    <>
      <header className={classes.header}>
        <h1>
          Delicious meals, created <span className={classes.highlight}>by you</span>
        </h1>
        <p>Choose your favorite recipe and cook it yourself. It is easy and fun</p>
        <p className={classes.cta}>
          <Link href="/meals/share">
            Share Your Favorite Recipe
          </Link>
        </p>
      </header>
      <main className={classes.main}>
โ—ผ๏ธŽ        <Suspense fallback={<p className={classes.loading}>Fetching meals...</p>}>
          <Meals/>
โ—ผ๏ธŽ        </Suspense>
      </main>
    </>
  );
}

 

728x90
๋ฐ˜์‘ํ˜•
LIST

๋Œ“๊ธ€