Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

likeornament 님의 블로그

[Next.js]Next.js 15의 페이지 컴포넌트, 이제는 params와 searchParams만 사용한다 본문

공부/next.js

[Next.js]Next.js 15의 페이지 컴포넌트, 이제는 params와 searchParams만 사용한다

likeornament 2025. 4. 14. 17:10

진행하던 프로젝트의 완성된 기능만이라도 배포하자는 백엔드의 말에, 배포용 파일을 만들고 오류를 수정하던 중 흥미로운 현상을 발견했다.

// word/learn/page.tsx
type Props = {
  isReview?: boolean,
}

export default function WordLearnPage({ isReview=false }: Props) {
  const [currentWordIndex, setCurrentWordIndex] = useState<number>(0);
  ...
}

단어 학습 페이지인 WordLearnPage를 복습 페이지에서도 재사용하기 위해, isReview라는 값을 props로 받을 수 있도록 코드를 작성했다.

 

//word/review/page.tsx
export default function WordReviewPage() {
  return (
    <WordLearnPage isReview={true}/>
  )
}

그리고 복습 페이지인 WordReviewPage에서 이 컴포넌트를 그대로 사용했는데...

 

Error: Invalid props passed to page component. 
Only `params` and `searchParams` are allowed.

이런 오류가 발생했다.

"params랑 searchParams만 허용된다고?"
조사해보니, 이는 Next.js가 14 버전에서 15버전으로 올라가며 변경된 사항이었다.

 



✅ 왜 이런 변화가 생겼을까?


1. 서버 컴포넌트의 명확한 인터페이스 유지를 위함

 

page.tsx는 기본적으로 서버 컴포넌트로 동작한다.

서버 컴포넌트는 브라우저가 아닌 서버에서 실행되어, 완성된 HTML을 클라이언트에 전달하는 구조다.

 

Next.js 팀은 서버 컴포넌트가 받을 수 있는 props를 params와 searchParams로 제한함으로써

  • 예측 가능한 동작을 보장하고,
  • 클라이언트/서버 간 혼동을 줄이려는 목적을 가진다.

2. page.tsx는 라우팅 시스템과 긴밀하게 연결된 구조이기 때문

 

page.tsx는 URL과 직접 매핑되는 컴포넌트다.

 

Next.js는 이 파일에 동적 라우트 값params쿼리스트링searchParams자동으로 전달한다.

 

이처럼 Next.js의 라우팅 시스템에 최적화된 구조를 유지하기 위해, 기타 props 전달은 허용되지 않도록 설계된 것이다.

 


✅ 그럼 어떻게 수정해야 할까?

// word/learn/page.tsx
export default function WordLearnPage() {
  return (
    <Suspense fallback={
      <div className="flex justify-center items-center w-full h-screen">
        <LoadingSpinner size="md" />
      </div>
    }>
      <WordLearningContainer isReview={false} />
    </Suspense>
  )
}

위처럼 props를 직접 전달하는 대신, 클라이언트 컴포넌트(WordLearningContainer)로 분리한 후 해당 컴포넌트에만 props를 넘겨주면 된다.

 

이때 WordLearningContainer는 클라이언트 컴포넌트이기 때문에 비동기적으로 로딩된다.
따라서 로딩되는 동안의 UI 공백이나 깜빡임을 방지하기 위해, <Suspense>로 감싸서 로딩 상태를 관리하는 것이 좋다.