URLSearchParams 기반 탭·필터·페이지네이션으로 SSR 상태를 유지하는 목록 컨트롤입니다.
탭·검색·페이지 상태를 모두 URLSearchParams 하나로 관리해, 새로고침·공유·뒤로가기에서도 같은 결과를 SSR로 재현할 수 있는 목록 컨트롤입니다.
결과 URL: /
function buildQuery(params: { type: string; q: string; page: number }) {
const sp = new URLSearchParams()
if (params.type) sp.set("type", params.type)
if (params.q) sp.set("q", params.q)
if (params.page > 0) sp.set("page", String(params.page))
const qs = sp.toString()
return qs ? `?${qs}` : ""
}
// 서버 컴포넌트: searchParams prop이 URL과 항상 동기화된 단일 진실원천이다.
export default async function Page({ searchParams }: { searchParams: Promise<Record<string, string>> }) {
const sp = await searchParams
const items = await fetchItems({ type: sp.type, q: sp.q, page: Number(sp.page ?? 0) })
return <List items={items} params={sp} />
}탭·검색어·페이지 조합이 실제로 어떤 URL로 직렬화되는지 보여주는 예시입니다. 같은 buildQuery 함수 하나로 세 컨트롤의 href를 모두 만든다.
//?type=guide/?type=guide&q=%EC%84%A4%EC%A0%95/?type=guide&q=%EC%84%A4%EC%A0%95&page=1buildQuery({ type: "", q: "", page: 0 }) // "" (기본값 → 루트 경로)
buildQuery({ type: "guide", q: "", page: 0 }) // "?type=guide"
buildQuery({ type: "guide", q: "설정", page: 0 }) // "?type=guide&q=설정"
buildQuery({ type: "guide", q: "설정", page: 1 }) // "?type=guide&q=설정&page=1"