본문 바로가기
C.W.K.
Stream
Lesson 02 of 10 · published

page.tsx가 받는 값

~22 min · page, params, Promise

Level 0호기심
0 XP0/68 lessons0/11 achievements
0/120 XP to next level120 XP to go0% complete

페이지는 기본 내보내기 컴포넌트야

page.tsx는 기본 내보내기로 React 컴포넌트를 제공해. 별도 지시가 없으면 서버 컴포넌트이므로 함수를 async로 만들고 그 자리에서 데이터를 기다릴 수 있어. 프레임워크가 페이지에 주는 라우팅 값은 paramssearchParams 두 가지야.

  • params에는 [slug]처럼 폴더 이름에서 잡은 동적 구간이 들어와.
  • searchParams에는 URL의 질의 문자열이 들어와.

Next.js 15부터 둘 다 Promise야

14에서 15로 넘어오며 가장 놓치기 쉬운 변경이야. 서버 페이지에서는 await paramsawait searchParams처럼 기다린 뒤 값을 꺼내야 해. 클라이언트 컴포넌트에서 Promise를 받았다면 React.use(params)로 풀어. Promise로 감싼 덕분에 프레임워크는 경로 값이 준비되는 동안 다른 렌더링 작업을 먼저 시작할 수 있어.

문자열 경로에서 타입을 얻을 수도 있어

Next.js가 제공하는 PageProps<'/blog/[slug]'> 같은 도우미를 쓰면 실제 라우트 문자열을 바탕으로 params 타입을 만들 수 있어. 경로 이름을 바꿨는데 수동 타입만 옛 모양으로 남는 실수를 줄여 주지. 버전이 다른 예제를 가져왔다면 동기 객체처럼 바로 구조 분해하고 있지 않은지부터 확인해.

페이지가 받는 paramssearchParams는 외부 입력이야. Promise를 기다린 뒤 schema나 허용 목록으로 값을 검증하고, 존재하지 않는 자원은 notFound()로 끝내. 타입 도우미는 키 이름의 실수를 잡지만 실제 URL에 들어온 값의 유효성까지 증명하지는 않아.

질의 문자열을 읽는다는 이유로 모든 로직을 페이지 함수에 몰 필요는 없어. 페이지는 값을 해석해 도메인 컴포넌트에 넘기고, 정렬·필터 같은 규칙은 테스트 가능한 순수 함수로 빼. 프레임워크가 주입한 값과 제품 규칙의 경계가 분명해야 경로를 바꿔도 로직이 남아. 동적 값과 질의 문자열을 함께 쓰는 페이지에 정상 경로, 빠진 구간, 반복된 질의 키, 허용 범위 밖 값을 보내 봐. await를 빼면 타입과 실행이 어떻게 실패하는지 확인하고, 폴더를 [slug]에서 [postId]로 바꿨을 때 PageProps 타입도 따라오는지 봐. 404와 검증 오류가 서로 다른 응답을 만드는지도 확인해.

Code

params를 기다리는 비동기 페이지·tsx
// app/blog/[slug]/page.tsx
type Props = {
  params: Promise<{ slug: string }>;
  searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
};

export default async function BlogPost({ params, searchParams }: Props) {
  const { slug } = await params;
  const { sort = 'newest' } = await searchParams;
  const post = await fetchPost(slug, { sort });

  return (
    <article>
      <h1>{post.title}</h1>
      <p className="text-sm text-gray-500">sort: {sort}</p>
      <div dangerouslySetInnerHTML={{ __html: post.html }} />
    </article>
  );
}
PageProps로 타입 적용하기·tsx
import type { PageProps } from 'next';

export default async function Page({ params }: PageProps<'/blog/[slug]'>) {
  const { slug } = await params; // 타입: { slug: string }
  return <Article slug={slug} />;
}
클라이언트 컴포넌트에서 읽기·tsx
'use client';
import { use } from 'react';

export default function ClientPage({
  params,
}: {
  params: Promise<{ slug: string }>;
}) {
  const { slug } = use(params); // React.use가 Promise를 풀어
  return <div>Slug: {slug}</div>;
}

External links

Exercise

paramssearchParams를 쓰는 페이지를 골라 둘 다 await로 읽고 PageProps 타입을 적용해. 정상·누락·잘못된 URL에서 회귀가 없는지 확인해.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.