ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [React] Suspense
    프로그래밍/React 2023. 11. 22. 15:42

    개요

    • Suspense의 개념 및 동작방식
    • Usages

    Suspense

    React에서 무언가를 기다릴 때 사용한다. (children이 로딩되기 전에 fallback을 보여준다)

     

    useEffect의 단점)

    • UI폭포(Waterfall)를 발생한다(상위 컴포넌트의 데이터부터 UI가 순차적으로 나타나는 것)
    • 초기랜더링 이후 발생하는 사이드 이펙트로, 데이터 로딩이 끝나면 리랜더링을 수행하기에 Race Condition에 취약

    이러한 단점을 보완해주는 Suspense

     

    예시)

    <Suspense fallback={<Loading />}>
      <SomeComponent />
    </Suspense>

    fallback에는 실제 UI가 로딩이 끝날 때까지 대신 보여줄 컴포넌트를 넣어준다 (스피너, 스켈레톤...)

    컨텐츠를 보여준 후 다시 suspend상태에 들어가게 되면 다시 fallback을 보여준다.

     

    동작방식)

    <Layout>
      <NavBar />
      <Sidebar />
      <RightPanel>
        <Post />
        <Suspense fallback={<Spinner />}>
          <Comments />
        </Suspense>
      </RightPane;>
    </Layout>

    위와 같은 구조의 트리에서 Comments에 대해 Suspense를 적용했을 때입니다.

    Comment가 suspend일떄와 완료되었을 때

    1. Comments를 제외한 나머지 컴포넌트를 먼저 받아옵니다. 이는 클라이언트가 처음 받는 HTML에는 Comments가 아닌 스피너로 대체 된 HTML을 받는다는 것을 의미합니다.
    2. 데이터가 준비되었다면 React는 같은 스트림으로 추가적인 HTML을 보내어 Suspned된 컴포넌트가 들어갈 자리에 새로운 컴포넌트를 갈아끼우는 코드가 들어갑니다.
    3. 아직 Hydration을 거치지 않아 유저 인터렉션을 수행할 수 없는 상태에입니다. (기존 SSR과 달리 Suspense를 통해서 컴포넌트 단위의 Hydration이 가능하게 됨)

    여러개의 Suspense를 사용했을 때 React는 어떻게 행동할까?

    <Layout>
      <NavBar />
      <Suspense fallback={<Spinner />}>
        <Sidebar />
      </Suspense>
      <RightPane>
        <Post />
        <Suspense fallback={<Spinner />}>
          <Comments />
        </Suspense>
      </RightPane>
    </Layout>

    Suspense가 두개 있기 때문에 Hydration도 각기 일어나게 됩니다.

    1. Suspense이외의 나머지 컴포넌트는 HTML랜더링과 Hydration이 일어나게 된다
    2. 이후 먼저 찾아지는 Suspense 바운더리가 Hydration을 실행한다.
    3. 이때 Hydration이 진행되는 컴포넌트가 아닌 다른 컴포넌트가 유저 인터렉션을 받게 된다면?
    4. React는 클릭 이벤트가 발생한 컴포넌트를 먼저 동기적으로 Hydrating한다.


    Usages

    가장 기본적 예시

    <Suspense fallback={<Loading />}>
      <Albums />
    </Suspense>

    주의사항)

    • Suspense의 children에서 데이터를 이벤트핸들러나 useEffect로 가져온다면 Suspense는 감지하지 못한다
    • Next.js와 같은 프레임워크에서 자주 사용되고 React만 사용한다면 큰 의미가 없다

    컨텐츠 여러 개를 동시에 보여주고 싶을 때 (promiseAll 같은 느낌)

    <Suspense fallback={<Loading />}>
      <Biography />
      <Panel>
        <Albums />
      </Panel>
    </Suspense>

     

    각 컨텐츠의 타이밍이 다를 때

    <Suspense fallback={<BigSpinner />}>
      <Biography />
      <Suspense fallback={<AlbumsGlimmer />}>
        <Panel>
          <Albums />
        </Panel>
      </Suspense>
    </Suspense>
    • Biography 컴포넌트는 Albums 컴포넌트가 로딩되기를 기다리지 않아도 된다.
    • 한번에 보여줄지, 특정 단위별로 보여줄지 결정할 수 있다.

    데이터가 불러와지는 동안 이전의 데이터를 보여주고 싶다면?

    import {useDeferredValue} from 'react'
    
    const deferredQuery = useDeferredValue(query);
    ...
    <Suspense fallback={<h2>Loading...</h2>}>
      <SearchResults query={deferredQuery} />
    </Suspense>
    • 이전 결과값을 유지하여 보여줄 수 있는 방법

     

     

    참고자료 : 블로그1

     

    댓글

Designed by Tistory.