먼저 아래의 예시를 보자.
const HomePage = () => {
const [loadedmeetups, setLoadedMeetups] = useState([]);
useEffect(() => {
setLoadedMeetups(DUMMY_MEETUPS);
}, []);
return <MeetupList meetups={loadedmeetups} />;
};
export default HomePage;
너무나 익숙한 코드다. 컴포넌트에서 활용할 데이터를 모종의 방식으로 가져오고 있고, 그걸 state에 저장해 두었다가 또 다른 컴포넌트에 props로 넘겨주는 방식. 하지만 이 방식에는 한가지 문제가 있다.
바로 첫번째 렌더 사이클때는 데이터를 받아오기 전이므로 표시할 내용이 비어있다는 것이다. 설령 그것이 사용자가 알아차리기도 힘들 정도로 빠르게 데이터를 받아와서 화면에 뿌려준다고 해도 첫 렌더링시 state에 설정되는 데이터는 비어있다는 사실은 바뀌지 않는다. 그리고 이는 SEO에 악영향을 끼친다.
next.js 에선 이를 위해서 pre-rendering 기능을 제공하는데, 크게 두가지 방법으로 달성한다.
첫번째는 static generation, 두번째는 server-side rendering. 일반적으로는 static generation 을 많이 쓴다.
static generation 에서 사전 렌더링 되는 시점은 애플리케이션을 빌드하거나 next 프로젝트를 빌드하는 시점, 즉 프로덕션 빌드를 만들때이다.
그리고 프로덕션 빌드를 만든다는건 npm run dev 할때가 아니라 npm run build 할때를 의미한다. 그렇기에 일단 사이트가 배포되고 나면 그 사전 렌더링된 페이지는 변경되지 않는다.
데이터를 업데이트 했는데 사전 렌더링한 페이지도 바꿔야 한다면 해당 빌드 프로세스를 다시 시작하고 다시 배포해야 한다. 생각보다 귀찮게 들리지만 실제로 많은 어플리케이션에서 페이지가 항상 바뀌는 것이 아니기 때문에 일반적으로 많이 사용하는 방법이다.
import MeetupList from "../components/meetups/MeetupList";
const DUMMY_MEETUPS = [
{
id: "m1",
title: "A First Meetup",
image:
"https://thumb.tidesquare.com/tour/public/product/PRV3000078320/PRD3000545066/origin/5c3ba937-021a-4fa2-a325-d1a3178b994d.jpg",
address: "Some adress 5,12345 some City",
description: "this is a first meetup",
},
{
id: "m2",
title: "A second Meetup",
image:
"https://thumb.tidesquare.com/tour/public/product/PRV3000078320/PRD3000545066/origin/5c3ba937-021a-4fa2-a325-d1a3178b994d.jpg",
address: "Some adress 5,12345 some City",
description: "this is a second meetup",
},
];
const HomePage = (props) => {
return <MeetupList meetups={props.meetups} />;
};
//이건 페이지 컴포넌트 파일에서만 export 할 수 있음.
//이 함수는 컴포넌트 함수를 호출하기 전에 호출됨
export async function getStaticProps() {
return {
props: {
meetups: DUMMY_MEETUPS,
},
};
}
export default HomePage;
위 예시 코드의 핵심은 getStaticProps 함수이다.
컴포넌트 함수를 호출하기 전에 호출된다
컴포넌트 함수에 넘겨줄 props를 미리 준비해 두는 역할을 한다.
서버에서 쓰는 코드도 쓸수 있으며 해당 함수 내에서 실행되는 코드는 클라이언트 쪽에선 절대로 실행되지 않는다.
빌드 과정에서 실행되는 코드이다.
반드시 객체를 리턴해야 하며, 보통은 이 객체 안에 컴포넌트 함수에 넘겨줄 props를 정의한다.
위 예시에서는 간단히 하드코딩한 더미 데이터를 사용하였지만 getStaticProps 함수 내에서 외부 데이터 api를 이용하는 식의 활용도 얼마든지 가능하다.
static generation 했을때 예상된는 문제는 역시 최신성 문제. getStaticProps가 준비해둔 props의 데이터가 outdated 된 상태일 수 있다.
그래서 쓰는게 getStaticProps에 추가해주는 revalidate.
export async function getStaticProps() {
return {
props: {
meetups: DUMMY_MEETUPS,
},
revalidate: 10,
};
}
이렇게 revalidate에 숫자를 지정해주면 지정된 숫자만큼의 '초'가 경과한 경우 데이터를 다시 요청한다. 위 예시처럼 10으로 지정되어 있다면 사용자에게 보여지는 데이터가 10초 이상 뒤쳐지지 않게 할 수 있다는 의미이다.
물론 이걸로도 부족할 수 있다. 진짜 매 요청때마다 무조건 반드시 최신 데이터를 보여줘야 하는 경우도 있을 것이다(주식 매도/매수창, 은행 거래창 등).
이런 경우에는 getStaticProps대신에 getServerSideProps 쓰면 된다. getServerSideProps는 빌드 프로세스 중에 실행되는 것이 아니고 빌드가 다 끝난 뒤 서버에서 실행된다.