SWR을 사용하면 만약 나의 계정 -> 채팅 -> 나의 계정으로 오는 과정에서 나의 계정에 해당하는 데이터가 캐시되어 캐시된 데이터를 사용합니다. (요청은 가지만 다르면 업데이트 합니다) 하지만 이전에 SSR getServerSideProps를 사용하게 되면, 기존에 SWR이 제공해 주는 캐시 기능을 사용할 수 없게 됩니다. 그냥 무조건 getServerSideProps즉 서버단에서 최신의 데이터를 가져와서 시간이 좀 걸리고 그 최신데이터를 렌더링하기 때문입니다.
또 에러가 나는 과정에서 서버단에서 만약 PlanetScale에 문제가 생겨 데이터를 받아 올 수 없는 경우가 생기게 된다고 해봅시다. 그럼 유저는 페이지에서 아무 것도 볼 수 없게 됩니다. UI자체를 불러올 수 없게 되버립니다. 하지만 SWR을 이용해서 클라이언트단에서 데이터를 불러오면 DB에 문제가 있따 하더라도 적어도 홈 타이틀이라던가 내비게이션 바는 볼 수 있습니다.
어떻게하면 getServerSideProps의 보안성과, SWR의 멋진 기능을 같이 사용할 수 있을까에 대해서 알아보도록 하겠습니다.
/pages/index.tsx
import type { NextPage } from "next";
import Layout from "@components/layout";
import Item from "@components/item";
import FloatingButton from "@components/FloatingButton";
import useUser from "@libs/client/useUser";
import Head from "next/head";
import useSWR, { SWRConfig } from "swr";
import { Fav, Product } from "@prisma/client";
import picture from "../public/local-image.jpg";
import Image from "next/image";
import client from "@libs/client/client";
interface ProductWithCount extends Product {
_count: {
favs: number;
};
}
interface ProductsResponse {
ok: boolean;
products: ProductWithCount[];
}
const Home = () => {
const { user, isLoading } = useUser();
const { data } = useSWR<ProductsResponse>("/api/products");
return (
<Layout title="홈" hasTabBar>
<Head>
<title>Home</title>
</Head>
<div className="p flex flex-col space-y-5 py-2">
{data
? data.products?.map((products) => (
<Item
key={products.id}
id={products.id}
title={products.name}
price={products.price}
hearts={products?._count?.favs || 0}
/>
))
: "Loading..."}
<FloatingButton href="/products/upload">
<svg
className="h-6 w-6"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M12 6v6m0 0v6m0-6h6m-6 0H6"
/>
</svg>
</FloatingButton>
</div>
</Layout>
);
};
const Page: NextPage<{ products: ProductWithCount[] }> = ({
products,
}) => {
return (
<SWRConfig
value={{
fallback: {
"/api/products": {
ok: true,
products,
},
},
}}
>
<Home />
</SWRConfig>
);
};
export async function getServerSideProps() {
console.log("SSR");
const products = await client.product.findMany({});
return {
props: {
products: JSON.parse(JSON.stringify(products)),
},
};
}
export default Page;
기존의 코드를 이와같이 바꾸면 됩니다. 새로운 Page라는 컴포넌트를 만들었고 여기에 SWR의 초기 캐시데이터를 서버사이드에서 getServerSideProps를 통해 주입해 주었습니다. 제가 서버사이드에는 Product에 대한 favs정보를 일부러 가져오지 않게했는데, 서버사이드에서 그냥 쌩 products를 가져오고 SWR을 이용해서 클라이언트 사이드에서 favs정보를 한번에 가져오면, SWR을 이후에도 계속 사용할 수 있게 할 수 있기 때문입니다.
그래서 초기 data.products?.favs를 0으로 주었고 클라이언트 사이드에서 주입이 되면 DB의 값으로 바뀌게 했습니다.
홈을 들어가면 좋아요가 0 -> DB값 으로 바뀌는 것을 확인할 수 있었습니다.
서버사이드에서 데이터가 잘 불러와져서 SEO도 최적화 된 것을 확인할 수 있습니다.
'Web > NextJs' 카테고리의 다른 글
[ Next.js - DeepDive ] - Blog Section (0) | 2022.08.06 |
---|---|
[ Next.js - DeepDive ] - SSR + Authentication (0) | 2022.08.06 |
[ Next.js - DeepDive ] - getServerSideProps (0) | 2022.08.06 |
[ Next.js - DeepDive ] - Script Component (0) | 2022.08.06 |
[ Next.js - DeepDive ] - _document and Fonts (0) | 2022.08.04 |