#35. Next.js 사전렌더링으로 데이터 가져오기

박현재·2020년 12월 28일
5
post-thumbnail

사전 렌더링

기본적으로 Next.js는 모든 페이지를 미리 렌더링합니다. 즉, Next.js는 클라이언트 측 JavaScript에서 모든 작업을 수행하는 대신 각 페이지에 대해 미리 HTML을 생성합니다. 생성된 각 HTML은 해당 페이지에 필요한 최소한의 JavaScript 코드와 연결됩니다. 브라우저에서 페이지를 로드하면 해당 JavaScript 코드가 실행되고 페이지가 완전히 상호작용합니다. 이 과정을 hydration이라고 합니다. 사전 렌더링은 더 나은 성능과 SEO를 가져올 수 있습니다.

사전 렌더링이 더 나은 성능과 SEO를 가져온다는 것은 반대로 react-hooks의 useEfftect() 함수를 사용할 경우 성능이 저하될 수 있다는 것을 뜻합니다. 아래 사진에서 처음에 렌더링하면서 undefined가 보였다가 한번 깜빡이고 데이터를 받아오는 것을 볼 수 있습니다. 페이지와 데이터가 많을수록 심한데, 사전 렌더링은 이러한 단점을 개선했습니다.

  1. useEffect()로 데이터를 불러오는 경우
  2. getInitialProps로 데이터를 불러오는 경우

    용량이 아주 작은 목데이터를 이용했기 때문에 차이를 크게 느끼기는 힘들지만, 깜빡임이 사라진 것을 확인할 수 있습니다.

사전 렌더링의 2가지 형태

  1. Static Generation : 빌드 시, HTML이 생성되고 각 요청에 재사용됩니다.
  2. Server-side Rendering : 각 요청에 대해 HTML이 생성됩니다.

Static Generation은 언제 사용할까요?

  • 마케팅 페이지
  • 블로그 게시물
  • 전자 상거래 제품 목록
  • 도움말 및 문서

dynamic SSG란?

동적라우팅([id].js)이 가능한 페이지의 Static Site Generation을 말합니다. getStaticProps와 getStaticPaths 모두 사용하여야 합니다.

데이터를 사용한 dynamic SSG

getStaticPaths를 사용하지 않는 경우 Server Error가 발생합니다.
=> Error: getStaticPaths is required for dynamic SSG pages ...

서버에서 데이터를 fetch 받을 때도 동적라우팅 주소를 사용해서 받아야합니다. ex) /detail/${id}

1) getStaticProps와 getStaticPaths를 사용하는 경우
/detail/[id].js


export async function getStaticPaths({ params }) {
	const res = await fetch("http://해당주소");
	const list = await res.json();
	const paths = list.map((list) => ({
		params: { id: list.id.toString() },
	}));
	return {
		paths,
		fallback: false,
	};
}

export async function getStaticProps({params}) {
	const res = await fetch(`http://해당주소/${params.id}`);
	const list = await res.json();
	return {
		props: { shows: list },
	};
}

2) getInitialProps를 사용하는 경우
/detail/[id].js

import React, { useEffect, useState } from "react";
import { useRouter } from "next/router";
import RequestDetailHeader from "../../../../components/Header/RequestDetailHeader";
import RequestInfoHeader from "../../../../components/Header/RequestInfoHeader";
import RequestInfo from "../../../../components/RequestDetail/RequestInfo";
import styles from "./Detail.scss";
import { REQUEST_NUMBER_TEXT } from "../../../../constants/requestDetail/RequestInfo";
import { PROPOSAL_INFO } from "../../../../constants/requestDetail/ProposalInfo";
import { PROPOSAL } from "../../../../constants/requestDetail/Proposal";
import fetch from "isomorphic-unfetch";

const Detail = (list) => {
  const isProposal = true;
  const { shows } = list;
  const router = useRouter();
  console.log(shows, "ddddddd");

  return (
    <div className={styles.container}>
      <RequestDetailHeader requestDetail={"요청상세"} />
      <RequestInfo list={shows} />
      <div style={{ paddingTop: "15px" }} />
      <RequestInfoHeader
        proposal={PROPOSAL}
        isProposal={isProposal}
        requestNumber={REQUEST_NUMBER_TEXT}
        proposalInfo={PROPOSAL_INFO}
        style={{ display: "none" }}
      />
    </div>
  );
};

Detail.getInitialProps = async function () {
  const res = await fetch("http://localhost:5700/api/getRequestInfo");
  const list = await res.json();
  console.log(list, "difjsdoifjwoj");
  return {
    shows: list,
  };
};

export default Detail;
profile
바로 하자, Right Now!

2개의 댓글

comment-user-thumbnail
2021년 1월 2일

당신 천재야...?

1개의 답글