NextJS ๊ณต์๋ฌธ์ ๐
pre-rendering
ํ๋ค. pre-rendering
ํ๊ธฐ ๋๋ฌธ์, ์ฌ์ฉ์ ๊ฒฝํ์ด ์ข๊ณ SEO
์ ์ต์ ํ๋์ด ์๋ค.NextJS์์๋ ๋๊ฐ์ง ํํ์ pre-rendering
๋ฐฉ์์ ์ ๊ณตํ๋ค. ์ธ์ HTML์ ๋ง๋๋์ ์ฐจ์ด๋ฅผ ๊ฐ์ง๊ณ ์๋ค.
Static Generation
์ ์ฌ์ฉํ๋ผ๊ณ ๊ถ์ฅํ๋ค.Sever-side Rendering
์ ์ด์ฉํด์ผ ํ๋ค.๊ธฐ๋ณธ์ ์ผ๋ก, ์ธ๋ถ data๋ฅผ ๊ฐ์ ธ์ฌ ํ์ ์๋ ํ์ด์ง๋ ์๋์ผ๋ก Static Generation
์ ํตํด pre-rendering ๋๋ค.
function About() {
return <div>About</div>
}
export default About;
// About page์ html ํ์ผ์ด ๋น๋ ํ์์ ๋ง๋ค์ด์ง. (data fetching X)
์ผ๋ถ ํ์ด์ง๋ pre-rendering์ ์ํด ์ธ๋ถ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์์ผ ํ ์ ์๋ค. (ํ์ผ ์์คํ
์ ๊ทผ, ์ธ๋ถ API ํธ์ถ ๋ฑ๋ฑ)
1. ํ์ด์ง ์ฝํ
์ธ ๊ฐ ์ธ๋ถ ๋ฐ์ดํฐ์ ์์กดํ๋ค. => getStaticProps
2. ํ์ด์ง ๊ฒฝ๋ก๊ฐ ์ธ๋ถ ๋ฐ์ดํฐ์ ์์กดํ๋ค. => getStaticPaths
// props๋ฅผ ์ ๋ฌ๋ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ด์ฉํ์ฌ ๋น๋ ํ์ ๋ html ํ์ผ ์์ฑ
function Blog({ posts }) {
return (
<ul>
{posts.map((post) => (
<li>{post.title}</li>
))}
</ul>
)
}
export default Blog;
// ์ด ํจ์๋ ๋น๋ ํ์๋ ํธ์ถ๋๋ค.
export async function getStaticProps() {
const res = await fetch('https://.../posts');
const posts = await res.json();
return {
props : { posts }, // ์ธ๋ถ์์ ๊ฐ์ ธ์จ ๋ฐ์ดํฐ๋ฅผ props๋ก ์ ๋ฌ
};
}
NextJS์์๋ Dynamic Routes๋ฅผ ์ด์ฉํ์ฌ ํ์ด์ง๋ฅผ ๋ง๋ค ์ ์๋ค.
pages/posts/[id].js
getStaticPath
๋ฅผ ์ฌ์ฉํ์ฌ ์ํ๋ ๊ฒฝ๋ก์ ํ์ด์ง๋ค์ ๋น๋ ํ์ ๋ pre-renderingํ๋๋ก ์ ํ ์ ์๋ค.function Post({ post }){
// Render post...
}
export default Post;
// ์ด ํจ์๋ ๋น๋ ํ์ ๋ ํธ์ถ๋๊ณ , pre-renderํ๊ณ ์ถ์ path๋ค์ ์ ํ ์ ์๋ค.
export async function getStaticPaths() {
const res = await fetch('https://.../posts');
const posts = await res.json();
// pre-renderํ๊ณ ์ถ์ path๋ค
const paths = posts.map((post) => ({
params: { id: post.id },
}));
// paths ๋ฐฐ์ด์ ์๋ ๊ฒฝ๋ก์ ํ์ด์ง๋ง ๋น๋ ํ์ ๋ pre-renderingํ๋ค.
// { fallback: false } : ๋ค๋ฅธ route๋ค์ 404
return { paths, fallback: false };
}
// ๋น๋ ํ์ ๋ ํธ์ถ
export async function getStaticprops({ params }){
const res = await fetch(`https://.../posts/${params.id}`);
const post = await res.json();
return { props : { post } }; // ์ธ๋ถ์์ ๊ฐ์ ธ์จ ๋ฐ์ดํฐ๋ฅผ props๋ก ์ ๋ฌ
}
Server-side Rendering
์ ์ด์ฉํ๊ธฐ ์ํด์ getServerSideProps
๋ฅผ export
ํ๊ฑฐ๋ getInitialProps
๋ฅผ ์ด์ฉํด์ผ ํ๋ค.
function Page({ data }) {
// Render data...
}
// ์ด ํจ์๋ ๋งค ์์ฒญ๋ง๋ค ํธ์ถ๋๋ค.
export async function getServerSideProps() {
const res = await fetch(`https://.../data`);
const data = await res.json();
return { props: { data } }; // ์ธ๋ถ์์ ๊ฐ์ ธ์จ ๋ฐ์ดํฐ๋ฅผ props๋ก ์ ๋ฌ
}
export default Page;
getServerSideProps
๋ ๋งค ์์ฒญ๋ง๋ค ์๋ฒ์ ์ํด ํธ์ถ๋๋ค.getStaticProps
์ ๋น์ทํ๊ฒ ์๊ฒผ์ง๋ง, ํจ์ ํธ์ถ ์์ ์ด ๋ค๋ฅด๊ณ , ๋ ๋๋ฆฌ๋ค.getInitialProps
๋ SSR
๋ฅผ ๊ฐ๋ฅํ๊ฒ ํ๋ค.
function Page({ stars }) {
return <div>Next stars: {stars}</div>
}
Page.getInitialProps = async (ctx) => {
const res = await fetch('https://api.github.com/repos/vercel/next.js');
const json = await res.json();
return { stars: json.stargazers_count };
}
export default Page;
getServerSideProps
๋ ํญ์ ์๋ฒ ์ฌ์ด๋์์ ์คํ๋์ง๋ง, getInitialProps
๋ ํด๋ผ์ด์ธํธ ์ฌ์ด๋์์๋ ์คํ๋ ์ ์๋ค.next/link
ํน์ next/router
๋ฅผ ํตํด ํ์ด์ง๋ฅผ ์ด๋ํ๋ ๊ฒฝ์ฐ ํด๋ผ์ด์ธํธ ์ฌ์ด๋์์ ์คํ๋๋ค.getInitialProps
๋ Automatic Static Optimization์ ์ง์ํ์ง ์๋๋ค. ๊ทธ๋์์ธ์ง ๊ณต์๋ฌธ์์์ getServerSideProps
๋ฅผ ์ฌ์ฉํ๋ผ๊ณ ๊ถ์ฅํ๋ค.๋ง์ฝ ํ์ด์ง๊ฐ ๋ณด์ฌ์ฃผ๋ ๋ฐ์ดํฐ๊ฐ ์ ์ ์ ๋ณด์ ๊ฐ์ด ๊ฐ์ธ์ ์ด๊ฑฐ๋, SEO์ ๊ด๋ จ ์๋ค๋ฉด ํด๋น ํ์ด์ง๋ฅผ pre-renderingํ ํ์๊ฐ ์๋ค. ์ด๋ด ๊ฒฝ์ฐ Client-side Rendering
์ ์ด์ฉํ๋ฉด ๋๋ค.
getStaticProps
๋ getServerSideProps
ํจ์๋ฅผ ์ฌ์ฉํ ํ์ ์์ด ํด๋ผ์ด์ธํธ ์ธก์์ api๋ฅผ ํธ์ถํ์ฌ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ ๋ ๋๋งํ๋ฉด ๋๋ค.
function Profile() {
const { data, status } = useQuery('/api/user', getUserInfo);
if (status === "loading") return <div>loading...</div>;
return <div>hello {data.name}!</div>;
}
๐ ํ์ด์ง์ ์ฑ๊ฒฉ์ ํ์ ํด์ ๋ ๋๋ง ๋ฐฉ์์ ์ ์ ํํด์ผ ๊ฒ ๋ค.