Carrot Market클론코딩을 하면서 클라이언트단에서 데이터를 불러오는 방식으로 앱을 만들었습니다. 이는 NextJS에서 데이터를 불러올 수 있는 여러 가지 방법 중 하나일 뿐입니다.
https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props
getServerSideProps
이 getServerSideProps는 서버단에서만 호출되고 페이지 컴포넌트가 서버단에서만 렌더링됩니다.
우리가 이 홈페이지에 들어왔다고 해 봅시다. 위의 상단바와, 하단바는 바로 파싱되어 나타납니다. 하지만 상품 목록들은 DB에서 데이터들을 불러와야 하기 때문에, 약간의 지연시간이 필요합니다.
따라서 우리에게는 두가지 선택지가 있습니다. 우리가 이전에 짰던거와 같이 HTML만 보여주고 로딩중인 것은 fallback을 보여주고 데이터가 다 받아와지면 그때서야 보여주는 것과, 상품 정보를 다 불러왔으면 한번에 HTML과 함께 보여주는 것입니다.
이제 두가지 방법에 대해 코딩하면서 간단히 알아보겠습니다.
/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 from "swr";
import { Fav, Product } from "@prisma/client";
import picture from "../public/local-image.jpg";
import Image from "next/image";
interface ProductWithFav extends Product {
favs: Fav[];
}
interface ProductsResponse {
ok: boolean;
products: ProductWithFav[];
}
const Home: NextPage = () => {
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(
({ id, name, price, favs }, i) => (
<Item
key={id}
id={id}
title={name}
price={price}
comments={1}
hearts={favs.length}
/>
)
)
: "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>
);
};
export default Home;
/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 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: NextPage<{ products: ProductWithCount[] }> = ({
products,
}) => {
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">
{products?.map((products) => (
<Item
key={products.id}
id={products.id}
title={products.name}
price={products.price}
comments={1}
hearts={products?._count?.favs}
/>
))}
<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>
);
};
export async function getServerSideProps() {
const products = await client.product.findMany({
include: {
_count: {
select: {
favs: true,
},
},
},
});
console.log(products);
return {
props: {
products: JSON.parse(JSON.stringify(products)),
},
};
}
export default Home;
이렇게 고칠 수가 있습니다. getServerSideProps를 이용해서 서버단에서 미리 API를 불러와서 HTML과 함꼐 불러온 것입니다. 결과를 한번 보시겠습니다.
다음과 같이 정상작동하는 것을 보실 수 있습니다.
하지만 이렇게 하게된다면 동네생활 -> 홈으로 갔을 때 SWR의 캐시기능을 활용할 수 없다는 점이 단점으로 뽑을 수 있겠습니다. 그래서 다음 포스팅에서는 어떻게 서버단에서 렌더링하고 SWR를 합칠 수 있는지 알아보도록 하겠습니다.
'Web > NextJs' 카테고리의 다른 글
[ Next.js - DeepDive ] - SSR + Authentication (0) | 2022.08.06 |
---|---|
[ Next.js - DeepDive ] - SSR + SWR (0) | 2022.08.06 |
[ Next.js - DeepDive ] - Script Component (0) | 2022.08.06 |
[ Next.js - DeepDive ] - _document and Fonts (0) | 2022.08.04 |
[ Next.js - DeepDive ] - Lazy-load Imports (0) | 2022.08.04 |