profile 페이지도 서버 사이드에서 렌더링해보자!
방법은 동일하다.
기본 내보내기한 컴포넌트만 getServerSideProps 함수 실행 시 데이터를 props으로 받을 수 있기 때문에 반드시 props를 받을 컴포넌트를 export default 해야 한다.
import useSWR, { SWRConfig } from "swr";
//
const Page: NextPage<{
profile: User;
}> = ({
profile,
}) => {
return (
<SWRConfig
value={{
fallback: {
"/api/users/me": { ok: true, profile },
},
}}
>
<Profile />
</SWRConfig>
);
};
export default Page;
마찬가지로 api 핸들러에 적힌 로직을 그대로 복사 붙여 넣기 하면 된다.
하지만 여기서 문제가 발생하는데..!! 바로 req.session.user를 사용하여 pscale에서 사용자 db를 찾아와야 하는데 여기서는 req를 사용할 수 없다는 없다는 사실!
import client from "@/libs/server/client";
//
export async function getServerSideProps() {
❌❌❌
const {
session: { user },
} = req;
❌❌❌
const profile = await client.user.findUnique({
where: { id: user?.id },
});
❌❌❌
return {
props: {
//profile
},
};
});
//
export default Page;
context 인자를 사용하여 이 문제를 해결해 보자.콘솔에 context를 찍어보면 req 오브젝트를 찾을 수 있는데, 여기에 암호화된 cookie도 있다.
import client from "@/libs/server/client";
//...
export async function getServerSideProps(context: NextPageContext) {
console.log(context.req);
//const profile = await client.user.findUnique({
// where: { id: user?.id },
//});
return {
props: {
//profile
},
};
});
//
export default Page;
context.req 오브젝트 안에 있는 암호화된 쿠키를 사용하여 세션을 얻어보자.이를 위해 iron session이 제공하는
withIronSessionSsr()을 사용하자.
withIronSessionSsr(handler, cookieOptions)
페이지를 렌더링할 때 next.js의 Server Side Rendering에서 session을 받아올 수 있는 함수이다.
withSsrSession(handler) 함수를 만들자.export function withSsrSession(handler: any) {
return withIronSessionSsr(handler, cookieOptions);
}
이 함수는 getServerSideProps 함수 자체를 핸들러 인자로 받아서
withIronSessionSsr(handler, cookieOptions)를 반환하는 함수로 만들거다.
따라서 위의 withSsrSession 함수의 역할은
withSsrSession 함수의 인자로 getServerSideProps() 함수 자체를 보내면, getServerSideProps의 인자인 context 안에 있는 req 안에 든 암호화된 쿠키를 사용할 수 있다.
withIronSessionSsr이 암호화된 쿠키를 풀어서 req 안에 쿠키 내용을 넣어 준다.
import { withSsrSession } from "@/libs/server/withSession";
import client from "@/libs/server/client";
//...
export const getServerSideProps = withSsrSession(async function ({
req,
}: NextPageContext) {
// console.log(context.req?.session.user);
//req.session.user에 있는 id 사용하여 유저 데이터 찾아오기
const profile = await client.user.findUnique({
where: { id: req?.session.user?.id },
});
return {
props: {
profile: JSON.parse(JSON.stringify(profile)),
},
};
});
//
export default Page;
getServerSideProps 함수 내용에 해당하는 부분을 withSsrSession() 함수로 감싸고 getServerSideProps 변수에 명명한다.
NextJS가 찾는 건 getServerSideProps니까 당연히 이렇게 해도 된다.
getServerSideProps의 함수 내용에 해당하는 handler를 withSsrSession() 함수의 인자로 보내면, context.req.session.user를 얻을 수 있으니 를 얻을 수 있으니 req.session.user.id를 사용하여 pscale에서 user db를 가져올 수 있고 props 키가 있는 오브젝트에 넣어서 반환하면 된다.
products data를 필요로 하는 홈 페이지 같은 데서는 req.session을 사용하여 인증할 필요가 없기 때문에 getServerSideProps 안에서 이런 인증 요청은 없어서 보다 간편하게 작성 가능했다.
하지만 프로필 페이지는 getServerSideProps 함수 안에서 인증 요청보내서 로그인된 유저가 누구인지 미리 알면 편하기 때문에 유저의 프로필을 server side에서 미리 렌더링 해서 초기 캐시값으로 설정하려고 getServerSideProps의 context 인자를 사용하여 서버 사이드에서 iron-session을 사용했다.
애초에 iron-session을 getServerSideProps 함수 안에 불러올 수도 있지만, 원래 하던 대로 /lib/server 에 작성해둔 파일 안에 withSsrSession()함수를 작성하고 이 함수를 import 해서 사용했다.
useSWR 사용해서 fallback 안에 컴포넌트의 캐시 초기값을 제공하면 useUser훅이 백그라운드에서 실행되기 때문에 사용자가 프로필 페이지에 접속 시 로딩 상태 없이 바로 렌더링된 페이즈를 볼 수 있다.
import useSWR, { SWRConfig } from "swr";
//...
const Page: NextPage<{
profile: User;
}> = ({
profile,
}) => {
return (
<SWRConfig
value={{
fallback: {
"/api/users/me": { ok: true, profile },
},
}}
>
<Profile />
</SWRConfig>
);
};
export default Page;
profile 페이지에서는 사용자의 profile 데이터 뿐만 아니라 reviews 데이터도 GET하고 있긴 한데, reviews 데이터는 굳이 사전 렌더링할 필요는 없어 보인다.
profile 페이지 처음 진입 시 리뷰가 깜빡이며 나타나긴 하지만 profile 페이지에서 더 중요한건 유저의 프로필 정보이니 옵션인 리뷰 데이터는 그냥 두기로 하고 넘어가겠음!