[에러 해결 / Next.js] useSearchParams() should be wrapped in a suspense boundary at page ...

마리 Mari·2026년 2월 20일
post-thumbnail
⚙️ 환경
- next: 16.1.0
- @suspensive/react: 3.17.2

배경

dev 환경에서는 잘 동작하는데 build 실행시 다음과 같은 에러가 발생했다.

useSearchParams() should be wrapped in a suspense boundary at page "{page file path}". Read more: https://nextjs.org/docs/messages/missing-suspense-with-csr-bailout

해결방법

useSearchParam을 사용하고 있는 컴포넌트를 Suspense로 감싸준다.

App router에서 useSeachParams()는 빌드 시점에 값을 알 수 없으므로, 이를 사용하는 컴포넌트가 바운더리 안에 없으면 해당 페이지 전체가 클라이언트 사이드 렌더링으로 빠지게 된다.

이미 use client를 통해 클라이언트 컴포넌트로 선언을 해두었으니 괜찮지 않나 싶었지만, use clientsuspense로 감싸는 것은 의미가 살짝 다르다.

  • use client 선언 : 클라이언트에서 하이드레이션을 하도록 명력
  • suspense boundary 추가: 하위 컴포넌트 로딩시까지 대기, 렌더링을 어디서 끊을지를 결정

때문에 페이지에서 어떤 부분을 먼저 정적 렌더링 하고, 어떤 부분을 클라이언트에서 채워넣을지 명시하여, 페이지 전체가 클라이언트 렌더링으로 전환되는 것을 방지해야 한다.

개선하기

useSearchParam을 쓰는 컴포넌트를 쓸때마다 suspense로 감싸기는 조금 귀찮다. 더불어 다른 개발자가 해당 컴포넌트를 가져다 사용한다고 할때, Suspense boundary를 추가하라고 말해주기도 현실적으로 어려운 일이다.

이때 컴포넌트 자체를 Suspense로 감싸서 export 하면 이러한 수고를 줄일 수 있다.

  • react suspense 사용 시

    const ClientComponent = (props) => {
      const searchParam = useSearchParam();
      // ...
    }
    
    const SuspenseClientComponent = (props) => {
      return (
        <Suspense fallback={null}>
          <ClientComponent {...props} />
        </Suspense>
      );
    }
    
    export default SuspenseClientComponent;
  • @suspensive/react 사용 시

    import { Suspense } from '@suspensive/react';
    
    const ClientComponent = (props) => {
      const searchParam = useSearchParam();
      // ...
    }
    
    export default Suspense.with(
      {
        clientOnly: true,
        fallback: null,
      },
      ClientComponent
    );

솔직히 suspensive 쪽이 훨씬 이쁘다.
사실 후자를 추천하려고 전자까지 적어봤다.

profile
우리 블로그 정상영업합니다.

0개의 댓글