Stream

hatban·2023년 5월 28일
0

Next.js 13에 대해서 공부하다가 발견한 Streaming.
Streaming에 대한 부분이 변화했다고 하는데 그게 loading.js 파일과
어떤 연관이 있는지 궁금해서 Streaming이 무엇인지 찾아보고자 했다


Streaming이란?

우선 Streaming의 작동 방식을 보기 전에, SSR의 렌더링 과정을 먼저 봐야한다

SSR의 렌더링 과정
1. 서버에서 페이지에 필요한 모든 데이터를 fetch한다
2. 서버는 html을 렌더한다
3. 페이지에 필요한 html, css, js를 클라이언트에게 보낸다
4. interactive 하지 않은 ui요소들이 html과 css를 통해 보여진다
5. hydrate를 통해 ui요소들이 interactive해진다


이렇게 쪼갤 수 있는데, 즉 서버에서 html을 렌더하기 위해서는 모든 데이터가 fetch되어야지 렌더링을 할 수 있고, 클라이언트 측에서는 리액트는 모든 컴포넌트에 대한 코드가 와야지 hydrate를 할 수 있다.


Next.js는 non-interactive한 부분은 먼저 보여주기 때문에 로딩 성능 측면에서는 개선했으나, 어쨋든 서버에서 데이터를 fetch하는게 느리면 그 이후가 개선되어도 소용이 없다!

이때 Streaming은 페이지의 html을 청크단위로 쪼개고 점진적으로 서버에서 클라이언트로 보내게 하는 것이다.이렇게 하면 화면에 작은 것이라도 보여지게 해서, 모든 데이터가 로드되기 전에 화면이 보여질 것이다.

Streaming은 리액트 컴포넌트 모델에서 잘 작동하는데, 각각의 컴포넌트가 청크로 여겨지기 때문이다. 높은 우선순위를 갖거나 데이터에 의존적이지 않은 컴포넌트는 먼저 보내지고 따라서 hydration을 보다 빨리할 수 있다.

그리고 낮은 순위의 컴포넌트들은 데이터가 fetch된 후에 보내지게 된다.


이런식으로 하나의 time이였던게 컴포넌트 단위로 쪼개진 것을 확인할 수 있다.

첫번째 컴포넌트는 데이터가 필요없어서 바로 서버에서 html로 렌더링 돼서 바로 클라이언트로 보내진 것을 확인할 수 있다.

이런 streaming을 Next.js에서는 loading.js 혹은 Suspense boundaries를 통해 실행할 수 있다.

1. loading.js

Next.js 13버전에 등장한 예약 파일명

/app 디렉토리에 추가해서 사용할 수 있다

app
├── getServerSide
│   └── page.js
├── getStatic
│   └── page.js
├── globals.css
├── head.js
├── layout.js
├── loading.js // HERE!
└── page.js

skeletons이나 spinner 혹은 나중에 뜰 페이지에 대한 의미있는 사진이나 제목을 넣어, 사용자가 app이 지금 응답중이라는 사실을 제공하고 더 나은 UX를 제공할 수 있다

import React from "react";
import { use } from "react";

const TTB_KEY = "ttbhhbbcho1713001";

export default function Page() {
  const books = use(getBookData());

  return (
    <ul>
      {books.map((book) => {
        return (
          <li key={book.itemId}>
            <h1>{book.title}</h1>
            <p>{book.author}</p>
          </li>
        );
      })}
    </ul>
  );
}

export async function getBookData() {
  const res = await fetch(
    `http://www.aladin.co.kr/ttb/api/ItemList.aspx?ttbkey=${TTB_KEY}&QueryType=Bestseller&MaxResults=5&start=1&SearchTarget=Book&output=js&Version=20131101
`,
    {
      cache: "no-store", //SSR 방식이다
    }
  );
  const books = (await res.json()).item;
 
  setTimeout(() => {
    return books;
	  }, 2000); //2초뒤에 가져온값을 props로 전달하다 보니까 

}


그냥 확인을 위해서 간단하게 코드를 setTimeout으로 처리해봤다

우선 뜨는 것은 확인했다!

2. Supsense Boundary

  • 사용 조건이 조금 있다
import { Suspense } from 'react';
import Albums from './Albums.js';

export default function ArtistPage({ artist }) {
  return (
    <>
      <h1>{artist.name}</h1>
      <Suspense fallback={<Loading />}>
        <Albums artistId={artist.id} />
      </Suspense>
    </>
  );
}

function Loading() {
  return <h2>🌀 Loading...</h2>;
}

이런 loading화면 같은 경우에는 React Query를 사용하면 쉽게 관리할 수 있다

0개의 댓글