스파르타코딩클럽/내일배움캠프
렌더링 패턴
myinfo7091
2024. 12. 17. 15:35
/* eslint-disable @next/next/no-img-element */
// SSG
// 서버 컴포넌트에서는 fetch API를 통해 데이터를 직접 불러올 수 있다.
// build 시점에 데이터를 불러오기 때문에 터미널에 console.log로 데이터를 출력해볼 수 있다.
export default async function HomePage() {
const response = await fetch("http://localhost:4000/products");
const data: Product[] = await response.json();
console.log(data);
return (
<div>
<h1>Hello! Next.js HomePage</h1>
<div>
<div className="p-8 m-4">
{data.map((product) => (
<div className="flex border p-4 gap-4 rounded-md" key={product.id}>
<img
className="rounded-smr"
width={150}
height={150}
src={product.images}
alt={product.title}
/>
<div className="flex flex-col justify-between">
<div>
<h2 className="text-xl font-bold">{product.title}</h2>
<p className="text-sm">{product.description}</p>
<p className="mt-4 text-2xl">{product.price.amount}$</p>
</div>
</div>
</div>
))}
</div>
</div>
</div>
);
}
export interface Product {
id: string;
isNew: boolean;
handle: string;
availableForSale: boolean;
title: string;
description: string;
descriptionHtml: string;
options: { name: string; values: string[] }[];
price: { amount: string; currencyCode: string };
variants: {
id: string;
title: string;
price: string;
availableForSale: boolean;
}[];
images: string;
featuredImage: string;
seo: { title: string; description: string };
tags: string[];
updatedAt: string;
}
/* eslint-disable @next/next/no-img-element */
// SSR
// 사용자가 웹사이트에 접속하려고 시도할 때마다 새로 컨텐츠를 불러와서 렌더링한다.
// fetch 옵션에 cache: "no-store"를 추가하면 된다.
// fetch 안에서 캐싱되지 않기 때문에 매번, 새로고침할 때마다 데이터를 새로 불러오게 된다.
export default async function HomePage() {
const response = await fetch("http://localhost:4000/products", {
cache: "no-store",
});
const data: Product[] = await response.json();
console.log("렌더링되었습니다.");
return (
<div>
<h1>Hello! Next.js HomePage</h1>
<div>
<div className="p-8 m-4">
{data.map((product) => (
<div className="flex border p-4 gap-4 rounded-md" key={product.id}>
<img
className="rounded-smr"
width={150}
height={150}
src={product.images}
alt={product.title}
/>
<div className="flex flex-col justify-between">
<div>
<h2 className="text-xl font-bold">{product.title}</h2>
<p className="text-sm">{product.description}</p>
<p className="mt-4 text-2xl">{product.price.amount}$</p>
</div>
</div>
</div>
))}
</div>
</div>
</div>
);
}
export interface Product {
id: string;
isNew: boolean;
handle: string;
availableForSale: boolean;
title: string;
description: string;
descriptionHtml: string;
options: { name: string; values: string[] }[];
price: { amount: string; currencyCode: string };
variants: {
id: string;
title: string;
price: string;
availableForSale: boolean;
}[];
images: string;
featuredImage: string;
seo: { title: string; description: string };
tags: string[];
updatedAt: string;
}
"use client";
// CSR
// use client 선언 후 useState, useEffect Hook을 사용한다.
/* eslint-disable @next/next/no-img-element */
import React, { useEffect, useState } from "react";
import { Product } from "../page";
const fetchData = async () => {
const response = await fetch("http://localhost:4000/products");
const data: Product[] = await response.json();
return data;
};
const ProductList = () => {
const [data, setData] = useState<Product[]>([]);
useEffect(() => {
console.log("렌더링되었습니다.");
fetchData().then(setData);
}, []);
return (
<div>
<h1>ProductList</h1>
<div>
<div className="p-8 m-4">
{data.map((product) => (
<div className="flex border p-4 gap-4 rounded-md" key={product.id}>
<img
className="rounded-smr"
width={150}
height={150}
src={product.images}
alt={product.title}
/>
<div className="flex flex-col justify-between">
<div>
<h2 className="text-xl font-bold">{product.title}</h2>
<p className="text-sm">{product.description}</p>
<p className="mt-4 text-2xl">{product.price.amount}$</p>
</div>
</div>
</div>
))}
</div>
</div>
</div>
);
};
export default ProductList;
/* eslint-disable @next/next/no-img-element */
// ISR
// 정적 증분 생성: 특정 시간마다 재생성
// fetch 옵션에 next: {revalidate: (원하는 시간)}을 적용하면 된다.
export default async function HomePage() {
const response = await fetch("http://localhost:4000/products", {
next: {
revalidate: 3,
}
});
const data: Product[] = await response.json();
console.log("렌더링되었습니다.");
return (
<div>
<h1>Hello! Next.js HomePage</h1>
<div>
<h1>ProductList</h1>
<div>
<div className="p-8 m-4">
{data.map((product) => (
<div
className="flex border p-4 gap-4 rounded-md"
key={product.id}
>
<img
className="rounded-smr"
width={150}
height={150}
src={product.images}
alt={product.title}
/>
<div className="flex flex-col justify-between">
<div>
<h2 className="text-xl font-bold">{product.title}</h2>
<p className="text-sm">{product.description}</p>
<p className="mt-4 text-2xl">{product.price.amount}$</p>
</div>
</div>
</div>
))}
</div>
</div>
</div>
</div>
);
}
export interface Product {
id: string;
isNew: boolean;
handle: string;
availableForSale: boolean;
title: string;
description: string;
descriptionHtml: string;
options: { name: string; values: string[] }[];
price: { amount: string; currencyCode: string };
variants: {
id: string;
title: string;
price: string;
availableForSale: boolean;
}[];
images: string;
featuredImage: string;
seo: { title: string; description: string };
tags: string[];
updatedAt: string;
}