이제 이전에는 일정 최소 시간이 지난 후에, 다른 사용자가 페이지를 요청해야지만, getStaticProps가 실행되며 해당 페이지를 업데이트 해서 정적인 HTML파일로 반환해 줍니다.
하지만 ODR을 사용하게 되면, 수동으로 getStaticProps를 어디에서든지 작동시킬 수 있게 됩니다.
이게 무슨말이냐면, useSWR을 쓸 필요가 전혀 없다는 뜻이 됩니다. 로딩이 아예 필요 없게 됩니다. 그냥 ODR을 모든 페이지에 적용시키면 되기 때문입니다.
예를들어서 채팅방에 적용해도 되고, 유저가 새로운 상품을 등록하면 프론트단에서 HTML을 재생성하라고 지시를 내릴 수 있는 겁니다. 그래서 다음 유저가 홈페이지로 오게 되면 새로운 상품을 HTML페이지로 전달받게 됩니다. 제품 상세 정보도 마찬가지 입니다. 다 정적인 페이지로 만들 수 있게 됩니다. 기존처럼 로딩상태를 보여주는 CSR방식으로 코딩하지 않아도 된다는 이점이 있습니다.
우리는 이제 동네생활(community)페이지로 와서 새로운 글을 등록하면, ODR을 이용해서 getStaticProps를 다시 실행할 수 있도록 해 보도록 하겠습니다.
이를 위해서 우선 next의 가장 최신버전을 설치했습니다.
$npm install -s next@latest
/pages/community/index.tsx
import type { NextPage } from "next";
import Link from "next/link";
import Layout from "@components/layout";
import FloatingButton from "@components/FloatingButton";
import useSWR from "swr";
import { Post, User } from "@prisma/client";
import useCoords from "@libs/client/useCoords";
import client from "@libs/client/client";
interface PostWithUser extends Post {
user: User;
_count: {
wondering: number;
answers: number;
};
}
interface PostsResponse {
ok: boolean;
posts: PostWithUser[];
}
const Community: NextPage<PostsResponse> = ({ posts }) => {
// const { latitude, longitude } = useCoords();
// const { data } = useSWR<PostsResponse>(
// latitude && longitude
// ? `/api/posts?latitude=${latitude}&longitude=${longitude}`
// : null
// );
return (
<Layout title="동네 생활" hasTabBar>
<div className="space-y-8 px-4 py-2">
{posts.map((post) => (
<Link key={post.id} href={`/community/${post.id}`}>
<a className="flex cursor-pointer flex-col items-start pt-3">
<span className="flex items-center rounded-full bg-gray-100 px-2.5 py-0.5 text-xs font-medium text-gray-800">
동네질문
</span>
<div className="mt-2 text-gray-700">
<span className="font-medium text-orange-500">
Q.
</span>{" "}
{post?.question}
</div>
<div className="mt-5 flex w-full items-center justify-between text-xs font-medium text-gray-500">
<span>{post?.user?.name}</span>
<span>{post?.createdAt as any}</span>
</div>
<div className="mt-3 flex w-full space-x-5 border-t border-b-[2px] py-2.5 text-gray-700">
<div className="flex items-center space-x-2 text-sm">
<svg
className="h-4 w-4"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
></path>
</svg>
{/* <div>궁금해요 {post._count.wondering}</div> */}
</div>
<div className="flex items-center space-x-2 text-sm">
<svg
className="h-4 w-4"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"
></path>
</svg>
<div>답변 {post._count?.answers}</div>
</div>
</div>
</a>
</Link>
))}
<FloatingButton href="/community/write">
<svg
className="h-6 w-6"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"
></path>
</svg>
</FloatingButton>
</div>
</Layout>
);
};
export async function getStaticProps() {
console.log("BUILDING COMUNITY STATICALLY");
const posts = await client.post.findMany({
include: {
user: true,
},
});
return {
props: {
posts: JSON.parse(JSON.stringify(posts)),
},
// revalidate: 20,
};
}
export default Community;
/pages/api/posts/index.ts
import client from "@libs/client/client";
import withHandler, {
ResponseType,
} from "@libs/server/withHandler";
// prettier-ignore
import type { NextApiRequest, NextApiResponse, NextApiHandler } from "next";
import { withApiSession } from "@libs/server/withSession";
const handler = async (
req: NextApiRequest,
res: NextApiResponse
) => {
if (req.method === "POST") {
const {
body: { question, latitude, longitude },
session: { user },
} = req;
const post = await client.post.create({
data: {
question,
latitude,
longitude,
user: {
connect: {
id: user?.id,
},
},
},
});
await res.revalidate("/community");
res.json({
ok: true,
post,
});
}
if (req.method === "GET") {
console.log(req.query);
const {
query: { latitude, longitude },
} = req;
// @ts-ignore
const parsedLatitude = parseFloat(latitude.toString());
// @ts-ignore
const parsedLongitude = parseFloat(longitude.toString());
// 질문에, 질문자의 정보가 필요함
const posts = await client.post.findMany({
include: {
user: {
select: {
id: true,
name: true,
avatar: true,
},
},
_count: {
select: {
wondering: true,
answers: true,
},
},
},
where: {
latitude: {
gte: parsedLatitude - 0.01,
lte: parsedLatitude + 0.01,
},
longitude: {
gte: parsedLongitude - 0.01,
lte: parsedLongitude + 0.01,
},
},
});
res.json({ ok: true, posts });
}
};
export default withApiSession(
withHandler({
methods: ["GET", "POST"],
handler,
})
);
다음과 같이 getStaticProps에 revalidate값을 지워서 revalidate의 값을 default ( false )으로 설정해 주었습니다. 그리고 /api/posts를 호출하는 시점에 res.revalidate("/community")를 호출해서 ODR로 /community 정적 페이지를 갱신해 주었습니다.
진짜 잘 작동하는 것을 확인할 수 있습니다. 그 다음 포스팅에서는 dynamic path가 들어있는 페이지에서 ODR을 어떻게 활용하는지 확인해 보도록 하겠습니다.
'Web > NextJs' 카테고리의 다른 글
[ Next.js - DeepDive ] - Fallback (0) | 2022.08.12 |
---|---|
[ Next.js - DeepDive ] - Blocking SSG (0) | 2022.08.12 |
[ Next.js - DeepDive ] - Incremental site regeneration - 1 (0) | 2022.08.08 |
[ Next.js - DeepDive ] - Dynamic getStaticProps (0) | 2022.08.06 |
[ Next.js - DeepDive ] - Dynamic getStaticProps (0) | 2022.08.06 |