KimMinJun
Coding Note
KimMinJun
전체 방문자
오늘
어제
  • 분류 전체보기 (524)
    • Project (2)
      • 두드림 (2)
      • blog (0)
    • CS (1)
    • Web (31)
      • Vanilla JS (13)
      • TS (2)
      • React (7)
      • Next.js (6)
      • ETC (1)
      • Web Socket (1)
    • Docker (14)
    • Git (5)
    • ALGORITHM (11)
      • 정렬 (6)
      • 최단경로 (1)
      • 자료구조 (1)
      • 슬라이딩 윈도우 (1)
      • etc (2)
    • PS (444)
      • 백준 (190)
      • Programmers (114)
      • CodeUp (21)
      • STL (3)
      • 제코베 JS 100제 (50)
      • SWEA (0)
      • LeetCode (65)
    • IT (2)
    • React 공식문서 (번역, 공부) (11)
      • Quick Start (2)
      • Installation (0)
      • Describing the UI (9)
      • Adding Interactivity (0)
      • Managing State (0)
      • Escape Hatches (0)
    • Next.js 공식문서 (번역, 공부) (3)
      • Getting Started (2)
      • Building Your Application (1)

블로그 메뉴

  • 홈
  • 태그
  • 방명록
  • 관리

공지사항

인기 글

태그

  • 수학
  • Level 2
  • 문자열
  • Level 0
  • 다이나믹 프로그래밍
  • C++
  • 백준
  • string
  • LeetCode
  • codeup
  • 제코베 JS 100제
  • js
  • tree
  • Level1
  • 정렬
  • Level 1
  • C
  • programmers
  • recursion
  • 그래프

최근 댓글

최근 글

hELLO · Designed By 정상우.
KimMinJun

Coding Note

Web/Next.js

Next.js 16에서 useSearchParams() 사용 시 should be wrapped in a suspense boundary 에러가 발생한 이유와 해결 방법

2025. 12. 16. 17:50

문제 상황

Next.js 16(App Router)을 사용하는 프로젝트에서 `searchbar`컴포넌트를 구현하던 중,

URL 쿼리 스트링을 읽기 위해 `useSearchParams()`훅을 사용했다.

"use client";

import { useEffect, useState } from "react";
import { useRouter, useSearchParams } from "next/navigation";
import style from "./serachbar.module.css";

export default function Searchbar() {
  const router = useRouter();
  const searchParams = useSearchParams();
  const [search, setSearch] = useState("");

  const q = searchParams.get("q");

  // 이후 렌더링 ...
}

 

에디터와 개발 모드(`npm run dev`)에서 에러는 없었지만,

프로덕션 모드에서도 확인하기 위해 빌드(`npm run build`)를 수행하자 다음과 같은 에러가 발생했다.

 

에러 증상

⨯ useSearchParams() should be wrapped in a suspense boundary at page "/".
Read more: https://nextjs.org/docs/messages/missing-suspense-with-csr-bailout
  • 개발 서버에서는 에러가 발생하지 않음
  • 빌드 시에 위 문구가 뜨면서 빌드 실패
    • suspense boundary로 감싸야 한다는 에러가 출력됨

 

원인 분석 과정

1. `useSearchParams()`에 대해 알아보기

먼저, `useSearchParams()`에 관한 오류이기 때문에 해당 훅에 대해 알아보는게 먼저라고 생각했다.

물론, 에러 메시지에 참고할 링크도 친절하게 나와있지만 해당 훅부터 공식문서를 참고해보자고 생각했다.

https://nextjs.org/docs/app/api-reference/functions/use-search-params

 

Functions: useSearchParams | Next.js

API Reference for the useSearchParams hook.

nextjs.org

 

 

조금 내리다보면, 'Static Rendering' 부분에 `<SearchBar />` 컴포넌트를 구현한 예제가 있다.

그리고 그 바로 밑에 보면 `<SearchBar />` 컴포넌트를 사용하는 Page 컴포넌트가 있다.

import { Suspense } from 'react'
import SearchBar from './search-bar'
 
// This component passed as a fallback to the Suspense boundary
// will be rendered in place of the search bar in the initial HTML.
// When the value is available during React hydration the fallback
// will be replaced with the `<SearchBar>` component.
function SearchBarFallback() {
  return <>placeholder</>
}
 
export default function Page() {
  return (
    <>
      <nav>
        <Suspense fallback={<SearchBarFallback />}>
          <SearchBar />
        </Suspense>
      </nav>
      <h1>Dashboard</h1>
    </>
  )
}

코드를 보면, `<SearchBar />` 컴포넌트를 `<Suspense>`로 감싸서 구현한 것을 볼 수 있다.

 

2. Suspense Boundary

에러 문구를 해석해보면 다음과 같다.

`useSearchParams()`는 '/' 페이지에서 suspense boundary로 감싸져 있어야 한다.

 

위 예제로 suspense boundary를 어떻게 적용해야하는지 알았다.

그런데, suspense boundary란 무엇일까?

 

https://react.dev/reference/react/Suspense

 

<Suspense> – React

The library for web and native user interfaces

react.dev

리액트에서 제공하는 기능으로,

자식 요소들이 모두 로딩이 끝날때까지 fallback을 보여주는 컴포넌트이다.

 

3. 왜 <Suspense>를 사용해야 할까?

  const router = useRouter();
  const q = searchParams.get("q");

렌더링 중에 search params가 아직 준비되지 않으면,

Next.js는 렌더링을 멈추려 하지만 이를 감싸는 `<Suspense />`가 없어서 에러가 발생하는 것이다.

 

더 자세히 알아보기 위해서,

기존 에러메시이제 출력된 링크를 참고해보기로 했다.

https://nextjs.org/docs/messages/missing-suspense-with-csr-bailout

 

Missing Suspense boundary with useSearchParams

Using App Router Features available in /app

nextjs.org

 

들어가자마자 가장 위에 왜 이런 에러가 발생하는지 이유가 나온다.

Reading search parameters through useSearchParams() without a Suspense boundary
will opt the entire page into client-side rendering.
This could cause your page to be blank until the client-side JavaScript has loaded.

 

해석해보면 다음과 같다.

Suspense boundary 없이 useSearchParams()를 이용해서 search parameter를 읽는것은
모든 페이지를 CSR 방식으로 렌더링하게 한다.
이로 인해서 클라이언트에서 JavaScript가 로딩될때까지 페이지가 비어있을 수 있다.

 

1) Next.js(App Router)의 기본 렌더링은 "서버가 먼저 그려준다"

App Router에서는 기본적으로 서버 컴포넌트(RSC) 중심으로 렌더링된다.

즉, HTML이 서버에서 먼저 만들어져서 내려오고, 클라이언트 JS는 나중에 로딩된 후, 하이드레이션 된다.

 

2) 그런데 `useSearchParams()`는 '클라이언트 훅'이고, 경우에 따라 렌더링을 멈출 수 있다.

https://nextjs.org/docs/messages/deopted-into-client-rendering

 

Entire page deopted into client-side rendering

Using App Router Features available in /app

nextjs.org

공식문서에 따르면, Suspense boundary가 없으면

정적 렌더링시에 모든 페이지가 클라이언트 사이드에서 렌더링된다고 적혀있다.

 

정적 라우팅의 경우에, `useSearchParams()`훅을 호출하면

가장 가까운 Suspense boundary까지의 트리를 클라이언트 사이드에서 렌더링하게 한다.

Suspense가 없으면 대체 UI를 보여줄 방법이 없기 때문에,

이 상태로 서버가 HTML을 만들다가 중단되면, 사용자에게 보낼 완성된 HTML이 애매해진다.

 

그래서 Next.js는 해당 페이지는 서버에서 미리 렌더링하지 말고,

클라이언트에서 JS가 로드된 다음에 전부 렌더링, 즉 CSR이 되는것이다.

 

3) Suspense를 사용하면?

가장 가까운 Suspense Boundary까지만 CSR로 만들기 때문에,

나머지는 서버 SSR, 혹은 정적 렌더링을 유지할 수 있다.

 

즉, '페이지 전체 CSR'을 막고, 동적인 부분만 격리하는 용도로 사용되는것이다.

 

해결 방법

`<Searchbar />` 컴포넌트를 Suspense로 감싸서 렌더링한다.

import { ReactNode, Suspense } from 'react';
import Searchbar from '../../components/searchbar';

export default function Layout({ children }: { children: ReactNode }) {
  return (
    <div>
      <Suspense>
        <Searchbar />
      </Suspense>
      {children}
    </div>
  );
}
저작자표시 (새창열림)

'Web > Next.js' 카테고리의 다른 글

Next.js 15 / Image Component  (2) 2025.08.13
Next.js 15 / CSS Modules  (1) 2025.08.13
Next.js 15 / File system conventions - layout.js(ts)  (2) 2025.08.12
Next.js 15 + Supabase로 Kakao 로그인 구현하기 - 2  (1) 2025.08.11
    'Web/Next.js' 카테고리의 다른 글
    • Next.js 15 / Image Component
    • Next.js 15 / CSS Modules
    • Next.js 15 / File system conventions - layout.js(ts)
    • Next.js 15 + Supabase로 Kakao 로그인 구현하기 - 2
    KimMinJun
    KimMinJun

    티스토리툴바