
둘 다 현재 URL의 query string을 읽을 수 있게 해주는 기능이다. 차이점은 다음과 같다.
프로젝트를 Vercel로 배포하는 과정에서 로컬로 잘 되던 부분이 오류가 발생했다. 원인을 알아보니 다음과 같았다.
해당 클라이언트 컴포넌트의 코드는 다음과 같았다.
// PaymentComplete.tsx
"use client";
import { useSearchParams } from "next/navigation";
function PaymentComplete() {
const searchParams = useSearchParams();
const paymentId = searchParams.get("paymentId");
// 불필요한 코드 생략
}
공식 문서 및 구글링을 통해 해결 방법을 알아보았다.
공식 문서에서는 Suspense 경계로 (공식문서 넣기)
다음 두 방식 중 고민이 되었다.
Suspense 경계로 감싸는 방식 VS 서버에서 searchParams를 props로 전달하는 방식
두 방식의 장단점을 비교했을 때, 사실 클라이언트 컴포넌트의 로직을 바꾸는 것에 큰 부담은 없었다. 때문에 해당 부분을 제외하고 다른 장단점을 놓고 봤을 때 서버에서 searchParams를 props로 전달하는 방식이 훨씬 장점이 많다는 생각이 들어, 해당 방식을 사용하기로 결정했다.
결과적으로, 일관성 유지 및 불필요한 렌더링 단계 축소, SEO 최적화, 하이드레이션 개선 등의 이점으로 인해 안정적이고 효율적인 후자의 방식을 선택하게 되었다.
이 방식을 통해 배포 오류 및 렌더링 사이 불일치 문제를 해결할 수 있었다.
해결된 코드는 다음과 같다.
// page.tsx (서버 컴포넌트)
function PaymentCompletePage({
searchParams,
}: {
searchParams: { paymentId: string };
}) {
return (
<Page>
<PaymentComplete paymentId={searchParams.paymentId as string} />
</Page>
);
}
// PaymentComplete.tsx (클라이언트 컴포넌트)
function PaymentComplete({ paymentId }: { paymentId: string }) {
// 바로 paymentId를 사용할 수 있다.
}