React v18 버전부터 Suspense를 공식적으로 지원한다. Suspense는 컴포넌트 렌더링에 필요한 특정 작업이 완료되지 않았음을 React에게 알려주는 매커니즘이다. 이 특정 작업은 여러가지가 있겠지만 Data Fetching 같은 비동기 작업인 경우가 가장 많다. Suspense를 이용하면, 데이터를 다 불러오지 못한 컴포넌트의 렌더링을 잠시 중단시키고 Loading 화면 같은 다른 컴포넌트를 먼저 보여주도록 할 수 있다.

<aside> 💡 Suspense는 React Query, SWR 같은 Data Fetching 라이브러리와 함께 사용할 수 있도록 설계됐다. Data Fetching 라이브러리에선 옵션 인자를 전달하는 방식으로 Suspense 기능을 활성화 할 수 있다. 예를들어 useSWR에선 세번째 인자에 { suspense: true }를 넘기면 된다.

</aside>

Suspense 장점


Suspense를 사용하면 워터폴(Waterfall), 경쟁 상태(Race Condition)를 방지할 수 있다.

워터폴(Warterfall) 문제 해결

Data Fetching에서 워터폴 현상은 이전 Fetch 요청에 대한 응답이 도착해야 다음 Fetch 요청을 보낼 수 있는 상황을 말한다. User 컴포넌트에서 이름, 주소, 이메일 같은 유저 정보를 받아온 후 렌더링하고, Posts 컴포넌트에선 해당 유저(ID)에 대한 포스팅 정보를 요청하는 상황을 예로들 수 있다.

function User({ userId }) {
  const [loading, setLoading] = useState(false);
  const [user, setUser] = useState([]);

  useEffect(() => {
    // ...Fetch user data, update user state
  }, []);

  if (loading) return <p>Loading user...</p>;

  return (
    <div>
      <p>{user.name} 님이 작성한 글</p>
      <Posts userId={userId} />
    </div>
  );
}

function Posts({ userId }) {
  const [loading, setLoading] = useState(false);
  const [posts, setPosts] = useState([]);

  useEffect(() => {
    // ...Fetch posts data, update posts state
  }, []);

  if (loading) return <p>Loading posts...</p>;

  return (
    <ul>
      {posts.map(post => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
}
  1. (User 컴포넌트) 유저 데이터 요청 → 요청중엔 로딩 화면 표시 — 2초 소요
  2. (User 컴포넌트) 데이터 응답 → 유저 정보 렌더 → Posts 컴포넌트로 userId 전달
  3. (Posts 컴포넌트) userId에 대한 포스팅 데이터 요청 → 요청중엔 로딩 화면 표시 — 3초 소요
  4. (Posts 컴포넌트) 데이터 응답 → 포스팅 목록 렌더

User 컴포넌트에서 유저 데이터를 정상적으로 받아와야만 Posts 컴포넌트가 해당 유저에 대한 포스팅 정보를 요청할 수 있다. 포스팅 데이터를 받아오는덴 3초가 소요되지만 User 컴포넌트의 데이터 요청 때문에 2초를 더 기다려야 하는 문제가 발생한다. 이런 현상을 워터폴이라고 부른다.

flowchart LR

A(컴포넌트 렌더링) --> B(Data 요청)
subgraph Start fetching
B
end
B --> C("#34;로딩#34; UI 렌더링") --> D(Data 응답)
subgraph End fetching
D
end
D --> E(컴포넌트에 Data 반영)

Data Fetching 라이브러리를 사용하면 컴포넌트 트리 구조에 필요한 모든 데이터를 렌더링 이전에 받아와서 워터폴 문제를 해결할 수 있다. 하지만 모든 데이터를 받아올때까지 트리 구조에 있는 컴포넌트를 렌더링할 수 없는, 또 다른 문제가 발생한다.



flowchart LR

subgraph Start fetching
A(Data 요청)
end
A --> B(컴포넌트 렌더링)
B --> C("#34;로딩#34; UI 렌더링")
subgraph End fetching
D(Data 응답)
end
C --> D
D --> E(컴포넌트에 Data 반영)