| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
- 좋은글
- 파이썬 장고
- NextJs
- python Django
- Variable declaration
- 파이썬 제어문
- 파이썬 클래스
- django virtualenv
- Python
- 자바 기본타입
- activate 오류
- 도전
- Kotlin 클래스 속성정의
- Python Class
- git
- 파이썬
- 희망
- Kotlin 클래스
- 다중조건문
- 장고 가상환경
- Kotlin 조건문
- 강제 타입변환
- 클래스 속성
- Kotlin Class
- Kotlin If
- github
- 성공
- 넥스트js
- 파이썬 반복문
- Kotlin else if
- Today
- Total
키모스토리
#13. params, searchParams (15+ 버전 에서 지켜야 할 점) 본문
Next.js App Router에서 페이지/레이아웃 컴포넌트는 자동으로 params, searchParams를 받을 수 있어요.
둘 다 “라우팅에서 온 값”이지만 성격이 완전히 다릅니다.
1) params = 경로(Path) 파라미터
폴더 이름에 있는 동적 세그먼트가 params로 들어옵니다.
예시
파일: app/movies/[id]/page.tsx
URL: /movies/123
코드:
export default function Page({
params,
}: {
params: { id: string };
}) {
return <div>Movie ID: {params.id}</div>; // "123"
}
특징
- 라우트 구조로 결정됨 ([id], [...slug], [[...slug]])
- 보통 “리소스 식별자” (id, slug 등)
- 값은 문자열(또는 catch-all이면 string[])
catch-all 예시
app/blog/[...slug]/page.tsx
2) searchParams = 쿼리스트링(Query String)
URL의 ?key=value 부분이 searchParams로 들어옵니다.
예시
URL: /invoices?page=2&query=kim&status=paid
코드:
export default function Page({
searchParams,
}: {
searchParams: { page?: string; query?: string; status?: string };
}) {
return (
<div>
page={searchParams.page}, query={searchParams.query}, status={searchParams.status}
</div>
);
}
특징
- “필터/정렬/페이지네이션”에 주로 사용
- 값은 기본적으로 string | undefined
- 같은 키가 여러 번 나오면(예: ?tag=a&tag=b) 처리 방식이 케이스가 갈리므로 보통 직접 파싱/정규화합니다.
3) 언제 뭘 쓰면 좋은가 (실전 기준)
- params: “페이지 자체가 달라지는 기준”
- 상세 페이지 id (/customers/42)
- 카테고리 slug (/products/shoes)
- searchParams: “같은 페이지에서 목록 조건만 바뀌는 기준”
- 검색어, 상태 필터, 정렬, 페이지번호
- 예: /invoices?query=abc&page=3&status=pending
4) App Router에서 중요한 점 2가지
- Server Component에서 기본으로 사용 가능
page.tsx는 기본이 서버 컴포넌트라 DB 조회에 바로 활용 가능. - 값 타입은 문자열이라서 숫자/불리언은 직접 변환해야 안전합니다.
Next.js 15부터(App Router) page.tsx(그리고 layout, generateMetadata 등)에 주입되는 params, searchParams가 “Promise”로 바뀌었어요. 그래서 값을 쓰려면 **await(또는 React의 use()로 Promise 해제)**를 하는 방식이 “정석”이 됐습니다. Next.js+1
버전별 핵심 차이
- Next 14 이하: params, searchParams가 동기 객체
- Next 15+: params, searchParams가 Promise
추천 타입/코드
export default async function DashBoardDetail({
params,
searchParams,
}: {
params: Promise<{ id: string }>;
searchParams: Promise<{ page?: string; query?: string; status?: string | string[] }>;
}) {
const { id } = await params;
const { page = "1", query = "", status } = await searchParams;
const pageNo = Number(Array.isArray(page) ? page[0] : page) || 1;
return (
<main>
DashBoardDetail Page [{id}]
<p>page = {pageNo} / query = {query} / status = {String(status ?? "")}</p>
</main>
);
}
“async/await 강제냐?”
- 값을 읽는다면 사실상 강제예요. params/searchParams가 Promise라서요. Next.js
- 다만 페이지가 Client Component('use client')라서 async를 못 쓰는 경우에는,
import { use } from "react";
const { id } = use(params);
const sp = use(searchParams);
처럼 use()로 Promise를 해제할 수 있어요.
1) use()가 하는 일 (핵심)
✅ Promise를 use(promise)로 읽기
- use(promise)를 호출하면, Promise가 resolve될 때까지 해당 컴포넌트 렌더링이 잠시 멈추고(Suspense)
- resolve되면 값이 반환됩니다.
- reject되면 가장 가까운 Error Boundary로 전달됩니다. ko.react.dev
✅ Context를 use(SomeContext)로 읽기
- use(Context)는 useContext(Context)와 비슷하게 동작합니다.
- 차이점: useContext는 컴포넌트 최상단에서만 호출해야 하는 반면, use는 조건문/반복문 내부에서도 호출 가능하다고 문서에 명시돼 있어요. ko.react.dev
2) Next.js(App Router)에서 use()가 등장한 이유
Next.js 15+에서 page.tsx의 params, searchParams가 Promise로 주입됩니다.
그래서 값을 꺼낼 때 **await 또는 React의 use()**가 필요해요. Next.js
3) Server Component vs Client Component에서 권장 사용
Server Component(기본 page.tsx)
서버 컴포넌트에서는 async/await를 권장합니다. (React 문서도 서버에서 데이터는 await 선호)
export default async function Page({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params;
return <div>{id}</div>;
}
Client Component('use client')
클라 컴포넌트는 보통 async 컴포넌트를 못 쓰는 경우가 많아서,
- (A) 라우트 값 읽기: Next 제공 훅 사용 (useParams, useSearchParams) Next.js+1
- (B) “Promise props”를 넘겨받아 풀어야 한다: React use(promise) 사용 (Suspense/에러바운더리 필요) ko.react.dev+1
A 예시(라우터에서 직접 읽기):
'use client'
import { useParams, useSearchParams } from 'next/navigation'
export default function Client() {
const { id } = useParams<{ id: string }>()
const sp = useSearchParams()
const page = sp.get('page')
return <div>{id} / page={page}</div>
}
B 예시( Promise props”를 넘겨받아 풀어야 한다) :
"use client";
import * as React from "react";
export default function DetailClient({
params,
searchParams,
}: {
params: Promise<{ id: string }>;
searchParams: Promise<{ page?: string; query?: string; status?: string }>;
}) {
const { id } = React.use(params);
const { page, query, status } = React.use(searchParams);
return (
<section>
<div>id: {id}</div>
<div>page: {page}</div>
<div>query: {query}</div>
<div>status: {status}</div>
</section>
);
}
4) 주의할 점 2개
- use(promise)는 **렌더링 중에 멈춤(Suspense)**을 만들기 때문에, 보통 <Suspense fallback=...> 경계가 필요합니다. ko.react.dev
- Next에서 searchParams는 “Dynamic API”라서 사용하면 페이지가 요청 시점 동적 렌더링으로 전환될 수 있어요. Next.js
아래와 같은 규칙을 지키도록 하자!!!
- “서버 컴포넌트에서는 await로 통일”
- “클라 컴포넌트에서는 useParams/useSearchParams로 통일”
이렇게 프로젝트 규칙을 하나로 정리해서 코딩을 하도록 합시다
'Web Devlopment > NextJs' 카테고리의 다른 글
| #12. Deployment (0) | 2025.03.30 |
|---|---|
| #11. Tailwind CSS (0) | 2025.03.30 |
| #10. global css (0) | 2025.03.29 |
| #9. Error handling (0) | 2025.03.28 |
| #8. fetch - Promise.all, Suspense (0) | 2025.03.28 |
