상세 페이지를 동적 라우팅([id].tsx
)으로 만들고
각 페이지에 해당하는 데이터를 받아오는 API 요청에 페이지 경로( router.query
객체)를 이용하려고 했다.
pages/nearby/[id].tsx
export default function ProductDetail() { const router = useRouter(); const id = router.query.id; const { data } = useQuery(['productDetail'], axios.get(`${REQUEST_URL}/api/boards/${id}) ...
그러나 페이지에 접속하거나 새로고침 할 때 데이터를 불러오는 데 실패했다.
router.query.id
가 undefined로 나오며 500 에러가 뜬다.
해당 페이지 컴포넌트에서 console.log로 router
객체를 찍어보면 router.query
객체가 비어있다.
router.query
는 빈 객체({}
)isReady
는 false
공식 문서에 따르면
During prerendering, the router's
query
object will be empty since we do not have query information to provide during this phase. After hydration, Next.js will trigger an update to your application to provide the route parameters in the query object.
getServerSideProps
또는 getInitialProps
가 있는 경우 페이지를 요청할 때마다 렌더링한다. (Server-side Rendering.) Static Generation 방식의 페이지
- 요청 전에 build 단계에서 페이지를 미리 렌더링해서 요청이 올 때마다 재사용한다.
- 데이터 역시 build 시점에 받아온 데이터를 그대로 재사용한다.
Static Generation 방식으로 만들어진 페이지는 렌더링하는 동안(Hydration이 끝날 때까지도) 쿼리 정보를 알 수가 없다. (어떤 페이지를 요청할 지 아직 알 수 없으므로)
따라서 데이터 요청 시 쿼리 정보를 담아서 요청을 보내야 하는 해당 페이지인데, 아직 쿼리 정보가 없는(어떤 페이지를 요청할 지 알 수 없는) build 시점에 데이터 요청을 보내서 만들어지는 방식으로 페이지가 제공되고 있기 때문에 발생한 문제이다.
다음과 같은 경우, Hydration이 끝난 후 query 객체에 경로 매개변수를 제공하기 위해 업데이트(렌더링)가 trigger된다.
➡️ 실제로 쿼리 객체가 업데이트 되는 것을 볼 수 있지만, 보여지는 페이지는 여전히 요청 전 build 단계에서 만들어진 페이지이므로 브라우저 상에서는 제대로 받아온 데이터가 있는 페이지를 볼 수는 없다
SSR 방식을 사용하면 페이지 요청 시마다 서버로 데이터 요청을 보낼 수 있다.
getServerSideProps
함수의 context
parameter를 사용해 쿼리 정보를 컴포넌트에 props(id
)로 넘겨주고 컴포넌트에서 이를 이용해 상세 페이지 데이터를 요청 할 수도 있고, 아예 서버 쪽에서 상세 페이지 데이터를 요청해서 받아온 후 그대로 컴포넌트에 props로 넘겨줄 수도 있다.
나는 react-query를 사용해 여러 옵션들을 사용하고 페이지 상세 데이터의 캐시를 관리하고 싶었으므로 쿼리 정보(id
)와 페이지 상세 데이터(detailData
) 모두 props로 넘겨주었다.
getServerSideProps
함수의context
parameter를 사용해 쿼리 정보를 컴포넌트에 props(id
)로 넘겨주었다.getServerSideProps
함수를 사용해 상세 페이지의 데이터를 서버 측에서 요청해 받아와서 컴포넌트에 props(detailData
)로 넘겨주었다.
pages/nearby/[id].tsx
export async function getServerSideProps(context) { const { id } = context.params; // context를 사용해 만든 쿼리 정보 try { const res = await getProductDetail(id); // 상세 페이지 데이터 if (res.status === 200) { const datailData = res.data; return { props: { id, datailData } }; // 컴포넌트에 넘겨줄 props } return { props: { id } }; } catch (error) { console.log(error); return { props: { id } }; } } export default function ProductDetail({ id, datailData }: productDetailType) { // 서버에서 받아온 props const { data } = useQuery(['productDetail'], () => getProductDetail(id), { initialData: datailData, }); ...
getServerSideProps
- 페이지에서
getServerSideProps
함수를 export하는 경우 Next.js는getServerSideProps
가 반환하는 데이터를 사용하여 페이지를 pre-render한다.- 이때 함수는 페이지 요청마다 실행되고 함수가 반환하는 데이터는 페이지 컴포넌트의 props로 전달된다.
- 서버 측에서만 실행되며 브라우저에서는 실행되지 않는다.
레퍼런스