
모던 웹 어플리케이션에서 비동기 작업은 흔하게 일어난다. API를 통한 데이터 페칭, 컴포넌트를 로딩, 계산 작업을 실행하는 데 있어서 완료되기 까지 꽤 많은 시간이 소모된다. 리액트의 경우 특정 부분의 UI를 미리 렌더링하고 나머지 부분은 비동기적으로 처리하면서 성능을 향상시킨다.
리액트 버전 18에서 Suspense 라는 강력한 신 기능이 등장!
→ pending 상태에서 컴포넌트의 렌더링을 지연시키는 것.
리액트의 suspense가 어떻게 동작하는지 알아보기에 앞서, 함수형 컴포넌트에 대해서 이해해보자.
함수형 컴포넌트는 리액트 개발의 기초로, 자바스크립트 함수의 형태로 JSX를 반환한다. 함수형 컴포넌트는 간결하고, 테스트하기 쉬우며, Hooks의 도입으로 많은 인기를 얻었다.
리액트의 Suspense는 함수형 컴포넌트의 비동기화를 간단하게 처리할 수 있는 방법을 제공한다. Suspense를 사용하면, 데이터 페칭과 같은 비동기 작업이 완료되기 까지 특정 컴포넌트의 렌더링을 지연하는 것을 정의할 수 있다. 이를 통해 반응형 UI와 유저 경험을 원활하게 만들 수 있다.
함수형 컴포넌트에서, 데이터 페칭이나 다른 비동기 작업은 주로 useEffect Hook의 내부에서 이루어진다. 이 Hook의 문제점은 전체 컴포넌트 트리를 블럭하기 때문에 비동기 작업에 의존하지 않는 컴포넌트라 할지라도 블럭되게 된다.
리액트의 Suspense는 이러한 문제점을 간단한 방법으로 해결하여 함수형 컴포넌트를 비동기적으로 만든다. 비동기 작업이 완료되기 까지 지연시킬 컴포넌트를 정의하여, 반응형 UI와 사용자 경험을 향상시킬 수 있다.
이제 비동기 렌더링을 위한 리액트 Suspense의 구현을 예제를 통해 알아보자.
우선, Suspense를 사용하기 위해 set up 해야할 부분이 있다. 이 과정에서는 suspense에 필요한 구성 요소와 지연시킬 컴포넌트를 suspense의 바운더리로 감싸주는 과정이 이루어진다.
<Suspense fallback={<Loading />}>
<SomeComponent />
</Suspense>
Suspense 라는 component에는 다음과 같은 children 과 fallback props가 있다.
이제 기본 예제를 통해 Suspense의 사용법을 알아보자.
아래의 예제는 TV 프로그램 목록을 API 호출로 불러와서, 렌더링한다.
src/components/Shows/index.js
import { fetchShows } from "../fetchShows";
import * as Styles from "./styles";
const resource = fetchShows();
const formatScore = (number) => {
return Math.round(number * 100);
};
const Shows = () => {
const shows = resource.read();
return (
<Styles.Root>
<Styles.Container>
{shows.map((show, index) => (
<Styles.ShowWrapper key={index}>
<Styles.ImageWrapper>
<img
src={show.show.image ? show.show.image.original : ""}
alt="Show Poster"
/>
</Styles.ImageWrapper>
<Styles.TextWrapper>
<Styles.Title>{show.show.name}</Styles.Title>
<Styles.Subtitle>
Score: {formatScore(show.score)}
</Styles.Subtitle>
<Styles.Subtitle>Status: {show.show.status}</Styles.Subtitle>
<Styles.Subtitle>
Network: {show.show.network ? show.show.network.name : "N/A"}
</Styles.Subtitle>
</Styles.TextWrapper>
</Styles.ShowWrapper>
))}
</Styles.Container>
</Styles.Root>
);
};
export default Shows;
src/App.js
import React, { Suspense } from "react";
import "./App.css";
import Shows from "./components/Shows";
function App() {
return (
<div className="App">
<header className="App-header">
<h1 className="App-title">React Suspense Demo</h1>
</header>
<Suspense fallback={<p>loading...</p>}>
<Shows />
</Suspense>
</div>
);
}
export default App;
앞서, Suspense 의 기본 사용방법처럼 Shows 컴포넌트가 Suspense 컴포넌트로 감싸져 있고, fallback props에 컴포넌트 대신, loading… 이 들어가 있다.
즉, Shows 컴포넌트에서 TV 프로그램 리스트가 페칭되기 전까지는 loading… 문구가 표시되고, 페칭이 완료되면 Shows 컴포넌트가 렌더링된다.