기본적으로 next는 모든 페이지를 미리 렌더링 합니다. 미리 렌더링을 하여 html을 생성하게 되면 더 나은 성능과 SEO 이점을 얻을 수 있습니다.
next에는 두 가지 형태의 사전 렌더링이 존재합니다.
외부 데이터를 필요로 하지 않는다면 next는 빌드 시에 페이지를 렌더링하여 요청시마다 제공하게 됩니다.
외부 데이터를 필요로 한다면 서버 사이드 렌더링을 통하여 외부 데이터를 이용하여 렌더링을 한 후 HTML을 제공합니다.
이때 서버 사이드 렌더링에 대하여 next에서 제공하는 옵션이 있습니다. 이를 통해 서버 사이드 렌더링시 외부 데이터를 불러오는 법을 알아보고 효율적인 HTML을 제공하는 방법을 배워 봅시다.
github api를 활용하여 유저 정보와 레파지토리 데이터들을 불러온 후 github 레파지토리를 따라 만들어 보면서 next 라우팅을 다시 한 번 해보고, 다양한 방법으로 데이터를 받아보는 실습을 해볼 예정입니다.
next는 getServerSideProps
는 페이지의 데이터를 서버로부터 제공받는 기본 API를 가지고 있습니다. 이는 서버에서 데이터를 패치하여 초기 데이터를 전달하도록 구성이 되어 있습니다.
우선 서버에서 데이터를 패치하기 위해 isomophic-unfetch
모듈을 설치합니다.
yarn add isomophic-unfetch
github에서 제공하는 api 중에서 유저의 정보를 받아오는 api를 활용합니다. api의 경로는 다음과 같습니다.
서버에서 데이터를 받아오는 코드를 작성합니다.
// index.js
import fetch from "isomorphic-unfetch";
const index = ({ user }) => {
const username = user && user.name;
return <div>{username}</div>;
};
export const getServerSideProps = async () => {
try {
const res = await fetch("https://api.github.com/users/yourcarrot0214");
if (res.status === 200) {
const user = await res.json();
return { props: { user } };
}
return { props: {} };
} catch (error) {
console.log(error);
return { props: {} };
}
};
export default index;
getServerSideProps
는 서버측에서 props를 받아오는 기능을 합니다.getServerSideProps
에서 페이지로 전달해준 데이터를 서버에서 렌더링을 하게 됩니다.getServerSideProps
에서 리턴한 props 값들은 페이지의 props로 전달됩니다.getServerSideProps
와 동적 라우팅을 이용하여 원하는 유저의 정보를 서버에서 불러오는 기능을 구현해 봅시다.
유저명을 입력받기 위해서 index.js
파일을 수정합니다.
> index.js
import React, { useState } from "react";
import Link from "next/link";
const App = () => {
const [username, setUsername] = useState("");
return (
<div>
<label>
username
<input value={username} onChange={(e) => setUsername(e.target.value)} />
</label>
<p>{username} github 검색하기</p>
<Link href={`/users/${username}`}>
<a>검색하기</a>
</Link>
</div>
);
};
export default App;
/users/[name]
페이지로 이동하게 됩니다./users/[name]
페이지를 불러올 때 외부 데이터인 깃허브 유저의 정보를 불러오도록 합니다.
> pages/users/[name].jsx
import fetch from "isomorphic-unfetch";
const name = ({ user }) => {
const username = user && user.name;
return <div>{username}</div>;
};
export const getServerSideProps = async ({ query }) => {
const { name } = query;
try {
const res = await fetch(`https://api.github.com/users/${name}`);
if (res.status === 200) {
const user = await res.json();
console.log("username : ", user.name);
return { props: { user } };
}
return { props: {} };
} catch (error) {
console.log(error);
return { props: {} };
}
};
export default name;
[name]
값은 getServerSideProps
의 매개변수 값인 query로 받아올 수 있습니다.getStaticProps
는 빌드 시에 데이터를 불러와 결과를 json으로 저장하여 사용합니다. 따라서 일관된 데이터를 보여주게 됩니다.
> pages/static.jsx
const staticPage = ({ time }) => {
return <div>{time}</div>;
};
export const getStaticProps = async () => {
return { props: { time: new Date().toISOString() } };
};
export default staticPage;
getStaticProps
에서 props로 현재 시간을 time 값으로 전달합니다.yarn build
를 통해 애플리케이션을 빌드하면 위 이미지와 같은 결과를 얻을 수 있습니다.yarn start
로 빌드된 애플리케이션을 실행하여 /static
페이지로 접속하면은 전달된 time값이 출력되며 이는 새로고침을 해도 데이터가 변경되지 않습니다.때로는 props 데이터가 변경되기를 원할수도 있습니다. 로그인 이후 주기적인 로그인 상태 확인이라던가 말이죠. next는 9.5버전부터 만들어진 정적 데이터가 갱신될 수 있도록 옵션을 제공합니다.
export const getStaticProps = async () => {
return { props: { time: new Date().toISOString() }, revalidate: 3 };
};
revalidate
값을 number 타입으로 설정하면 해당 초 마다 데이터가 갱신됩니다.이번에는 동적 페이지에서 getStaticProps
를 사용해보도록 하겠습니다.
> pages/static/[name].jsx
import fetch from "isomorphic-unfetch";
const name = ({ user, time }) => {
const username = user && user.name;
return (
<div>
{username}
{time}
</div>
);
};
export const getStaticProps = async ({ params }) => {
try {
const res = await fetch(`https://api.github.com/users/${params.name}`);
if (res.status === 200) {
const user = await res.json();
return { props: { user, time: new Date().toString() } };
}
return { props: { time: new Date().toString() } };
} catch (error) {
console.log(error);
return { props: { time: new Date().toString() } };
}
};
export async function getStaticPaths() {
return {
paths: [{ params: { name: "yourcarrot0214" } }],
fallback: true,
};
}
export default name;
getServerSideProps
와는 다르게 query 대신 params를 사용합니다.getStaticPaths
를 통해 params를 미리 정의해야 합니다.getStaticpaths
는 페이지의 경로가 외부 데이터에 의존할 때 사용합니다.static/yourcarrot0214
페이지를 getStaticProps
를 사용하여 데이터를 저장하고 static/yourcarrot0214
에 접속할 때마다 미리 렌더링된 HTML을 제공합니다.yarn build
를 하게 되면 터미널에서 결과를 확인할 수 있습니다.getInitialProps
는 9.3버전 이전부터 서버 사이드 데이터 패치를 위해 사용되던 함수입니다. next는 9.3버전 이상부터 getServerSideProps
와 getStaticProps
를 사용하는것을 권장하고 있습니다.
getInitialProps
를 예제를 통해 알아봅시다.
> pages/users/[name].jsx
import fetch from "isomorphic-unfetch";
const name = ({ user }) => {
const username = user && user.name;
return <div>{username}</div>;
};
name.getInitialProps = async ({ query }) => {
const { name } = query;
try {
const res = await fetch(`https://api.github.com/users/${name}`);
if (res.status === 200) {
const user = await res.json();
console.log("username : ", user.name);
return { props: { user } };
}
return { props: {} };
} catch (error) {
console.log(error);
return { props: {} };
}
};
export default name;
독립된 함수가 아닌 컴포넌트의 함수에 getInitialProps
를 추가하는 방식으로 사용합니다.
빌드 후 '/'에 접속하여 유저 아이디를 검색하게 되면 users/[name]
페이지로 이동하게 됩니다. 이때 유저의 이름이 브라우저의 콘솔에 출력되는 것을 확인할 수 있고, 이후 새로고침시 값은 브라우저가 아닌 터미널에서 출력됩니다.
이는 getInitialProps
를 사용하게 되면 초기 렌더링 시에는 서버에서 데이터를 불러오지만 클라이언트측 네비게이션을 사용하게 되면 클라이언트측에서 데이터를 불러오는것을 의미합니다.
외부 데이터를 사용하는지에 따라
getServerSideProps
와getStaticProps
를 구분해서 사용하고, 초기 데이터를 외부에서 불러온 뒤 이후 클라이언트측 데이터를 불러오려면getInitialProps
를 사용하여 페이지를 렌더링 합니다.