Suspense란?
Suspense는 아직 렌더링이 준비되지 않은 컴포넌트가 있을때 로딩 화면을 보여주고 로딩이 완료되면 해당 컴포넌트를 보여주는 React에 내장되어 있는 기능입니다.
Suspense를 사용하려는 이유
- 복잡한 비동기 처리를 해결하기 위해
⇒ 로딩시 , 성공시, 실패시를 선언적으로 처리 가능
Suspense 도입을 고민하게 된 사례
- ReceivedPostListPage.tsx - isLoading, data값의 존재 유무등으로 처리
- Channel.tsx - 비동기 값을 한번더 비동기(useState)로 묶어서 사용
각 방법의 공통 문제점
- 받아온 데이터에 관한 처리가 복잡합니다. 지금은 성공시의 화면만 신경써서 data가 undefined일 때만 처리하고 있지만 실패시, 로딩시 화면까지 처리하려 한다면 더욱 복잡해집니다,
Suspense 사용시 이점
성공시 처리는 데이터가
undefined 가 아닌 상태를 보장하므로 위와 같은 처리가 필요없고 실패시, 로딩시는 ErrorBoundary, Suspense fallback ui로 선언적으로 나타낼 수 있습니다.Suspense 적용
tanstack query의 suspense
tanstack query에서 suspense 기능을 제공해줍니다.
v5부터 suspense=true는 deprecated되었고 대신
useSuspenseQuery, useSuspenseQueries, useSuspenseInfiniteQuery 훅을 제공해줍니다.

위의 3가지 훅을 사용할 시 타입 레벨에서
data가 undefined 상태가 되지 않습니다.⇒
undefined 인 상태에서는 Suspense에서의 fullback UI가 렌더링 되기 때문입니다.Suspense 사용
suspense를 사용할 mypage컴포넌트의 상위에 작성해줍니다. fallback에 로딩시 보여줄 컴포넌트를 작성합니다.
tanstack query hook 수정
useQuery → useSuspenseQuery
useQueries→ useSuspenseQueries
로 변경해주면 됩니다.
- ReceivedPostListPage.tsx

isLoading이 true가 되어도 data가 undefined인 경우가 있습니다. 때문에 따로 예외처리가 필요했는데 suspense훅을 사용할 경우 undefined가 아닌 타입을 보장해서 불필요한 코드를 줄일 수 있습니다.
수정후
- ReceivedPostListPage.tsx
- Channel.tsx
useChannelQuery를 suspenseQuery로 변경했기때문에 주석처리된 부분을 제거할 수 있습니다.
- AppRouter.ts
⚠ Suspense로 감싸주지 않으면 로딩되는 동안 보여줄 페이지가 없어서 오류가 발생하므로 반드시 감싸줘야 합니다.
적용 화면

ErrorBoundary
suspense의 fullback은 로딩중일때의 ui를 그리고 실패시의 ui는 ErrorBoundary에서 처리 가능합니다.
간편한 에러처리를 위해
react-error-boundary 라이브러리를 설치해서 사용했습니다.- App.tsx
각 pathname마다 다른 화면을 보여주기 위해 QueryErrorBoundary컴포넌트를 만들어 사용했습니다.
적용 화면

이렇게 하면 로딩중 컴포넌트, 성공시 컴포넌트, 실패시 컴포넌트를 선언적으로 각각 처리할 수 있습니다.
설명이 부족했다면 언제든 물어봐 주세요. 그리고 틀린 게 있거나 다른 더 좋은 방법이 있다면 언제든 공유해주시면 바로 반영하겠습니다!!
[참고자료]
- tanstack query suspense
- suspense
- errory boundary

