본문 바로가기
Next.js

[next.js]프리렌더링(정적생성, 서버사이드렌더링(SSR))

by 남민섭 2023. 12. 5.
728x90
반응형

프리렌더링(Pre-randering)

웹페이지 로딩 이전에 하는 렌더링

 

렌더링 과정

  1. 서버에서 HTML과 JavaScript 불러오기: 이 단계에서 Next.js는 페이지의 초기 버전을 빌드합니다. 이 초기 버전은 서버에서 생성된 정적 HTML로 구성되며, 클라이언트 측 JavaScript 번들도 포함합니다. 이 과정은 페이지가 빠르게 로드되도록 하며, 검색 엔진 최적화(SEO)에도 유리합니다.
  2. 리액트 실행: 사용자의 브라우저가 초기 HTML을 받은 후, 클라이언트 측 JavaScript가 실행되어 리액트를 시작합니다. 이 단계에서 리액트는 서버에서 받은 HTML과 동기화를 시도하며, 필요한 경우 추가적인 데이터를 가져오거나 사용자 인터랙션에 대응합니다.
  3. 클라이언트 사이드 렌더링에서 리액트가 화면 조정 (Hydration): 이 단계는 'hydration'이라고 불리며, 이때 리액트는 서버에서 렌더링된 HTML에 이벤트 핸들러 같은 동적 기능을 연결합니다. 이 과정을 통해 페이지는 완전한 리액트 애플리케이션으로 변모하며, 사용자와의 상호작용이 가능해집니다.(이미 랜더링된 html 와 리액트의 데이터를 연결하는 작업을 hydration이라고 한다)

그리고 프리렌더링은 이 과정 그러니깐 서버에서 데이터를 받아오기 전에 일어난다

 

이러한 과정을 통해 Next.js는 서버 사이드 렌더링(SSR)의 이점과 클라이언트 사이드 렌더링(CSR)의 동적 기능을 모두 활용할 수 있고 이 방식은 초기 페이지 로드 시간을 단축하고 사용자 경험을 향상시키는 데 도움이 됨

 

 

프리렌더링의 2가지 방법

  정적 생성
(Static Generation)
서버 사이드 렌더링
(Server Side Randering(SSR))
정의 정적 생성은 빌드 시간(build time)에 HTML 파일을 생성하는 방법
각 요청에 대해 서버가 HTML을 실시간으로 생성하는 방법
장점 페이지 로딩이 매우 빠름.

서버가 요청마다 HTML을 생성할 필요가 없기 때문에 서버 부하가 줄어들고 성능이 향상.
항상 최신 상태의 데이터를 제공할 수 있음.

사용자의 요청에 따라 동적으로 페이지를 생성할 수 있어 자주 변경되거나 사용자별 커스터마이즈가 필요한 페이지에 적합.
적용한 페이지 예시 블로그 게시물, 문서 페이지, 제품 목록  사용자 프로필, 실시간 정보가 필요한 대시보드, 사용자 인터랙션이 많은 애플리케이션 등

 

next.js에서는 코드를 작성하고 실행하면 우리도 모르게 정적 생성을 해준다.

※ 정적 생성(getStaticPaths( ), getStaticProps( ))함수와 서버 사이드 렌더링(getServerSideProps( ))함수는 같이 사용 할 수 없음

 

데이터 참고자료

https://jsonplaceholder.typicode.com/

 

JSONPlaceholder - Free Fake REST API

{JSON} Placeholder Free fake API for testing and prototyping. Powered by JSON Server + LowDB. Tested with XV. Serving ~2 billion requests each month.

jsonplaceholder.typicode.com

 

 

● 정적 생성 코드(getStaticPaths( ), getStaticProps( ))

 

 

 

pages/index.js

import { ThemeContext } from "@/context/ThemeContext";
import Image from "next/image";
import Link from "next/link";
import { useRouter } from "next/router";
import { useContext, useState } from "react";

// 정적 생성
export async function getStaticProps(context) {
  const res = await fetch("https://jsonplaceholder.typicode.com/posts");
  const result = await res.json();
  const users = result ?? [];

  return {   //리턴으로 반환해주는 값는 아래와 같은 객체형태여야한다(아니면 에러뜸)
    props: {
      users,
    },
  };
}

.....
  
  return (
    <>
      ....
      <h2>리스트</h2>   ////// 가져온 데이터
      {users.map((user) => {
        return (
          <Link key={user.id} href={`/next/${user.id}`}>
            <div
              style={{
                border: "1px solid #fff",
                marginBottom: "10px",
                width: "500px",
              }}
            >
              <h3>
                {user.id}.{user.title}
              </h3>
            </div>
          </Link>
        );
      })}
    </>
  );
}

 

▶ 다이나믹 라우팅 사용해서 정적생성

pages/prev/[id].js

import Link from "next/link";

// getStaticProps(context)에서 해당 id값이 필요하기 때문데
// getStaticPaths()함수에서 데이터 id 값들을 매핑해서 params 에 등록해준다
export async function getStaticPaths() {
  const res = await fetch("https://jsonplaceholder.typicode.com/posts/");
  const result = (await res.json()) ?? [];
  const paths = result.map((path) => ({
    params: { id: String(path.id) },
  }));
  return {
    paths,
    fallback: true, // 아래 내용 참고
  };
}

//
export async function getStaticProps(context) {
  const userId = context.params["id"];  //아래 내용 참고
  let user;

  try {
    const res = await fetch(
      `https://jsonplaceholder.typicode.com/posts/${userId}`
    );
    user = await res.json();
    if (!user || Object.keys(user).length === 0) {
      throw new Error("에러");
    }
  } catch {
    return {
      notFound: true, // 값이 없으면 404 페이지로 넘어감
    };
  }

  return {
    props: {
      user,
    },
  };
}

export default function next({ user }) {

  if (!user || Object.keys(user).length === 0) { 
  //데이터의 값이 없을 때 빈 객체를 넘겨줘서 이런 조건을 줬음
    return <div>로딩중입니다.</div>; // 404 페이지 넘어가기전에 로딩 걸림
  }

  return (
    <div>
      <h3>제목</h3>
      <h3>{user.title}</h3>
      <h3>내용</h3>
      <p>{user.body}</p>
      <Link href={"/"}>뒤로가기</Link>
    </div>
  );
}

 

 

1. fallback: 정적으로 생성되지 않은 경로에 대한 처리 방식을 설정( 3가지 값이 있음 )

false  - 반환된 경로들만 정적으로 생성.
 - 미리 생성되지 않은 경로에 접근하면, 404 페이지가 표시.
 - 필요한 모든 경로가 빌드 시점에 알려져 있고 추가적인 경로가 필요 없는 경우에 적합
true  - 반환되지 않은 경로에 대한 페이지 요청 시 사용자에게 먼저 빈 페이지가 보여짐.
 - 페이지가 생성되면, Next.js는 빈 페이지를 완전한 페이지로 교체함
 - 이 방법은 필요한 경로가 많거나, 사용자가 접근할 수 있는 경로가 빌드 시점에 알려져 있지 않을 때 유용
 - 첫 번째 사용자는 페이지가 생성되는 동안 대기해야 하지만 이후에는 누구나 생성된 페이지를 볼 수 있음.
blocking  - true 와 비슷하게 작동하지만 사용자가 빈 페이지를 보는 대신 페이지가 서버에서 완전히 생성될 때까지 대기함
 - 생성된 페이지는 클라이언트에 직접 전달되므로 사용자는 빈 페이지를 볼 필요가 없
 - 사용자에게 빈 페이지를 보여주지 않으면서도 필요에 따라 페이지를 동적으로 생성하고 싶을 때 적합

 

2. context  속성 : 페이지 생성을 위한 추가적인 데이터나 파라미터를 제공하기 위해 사용

params  동적 라우팅을 사용하는 페이지의 경우 현재 페이지에 대한 경로 매개변수(route parameters)를 포함
 ex) [id].js
 각 데이터를 매핑해서 id값을 추출해서 params에 등록해준다 (params: { id: 값 })
preview  페이지가 프리뷰 모드(preview mode)에서 렌더링되고 있는지 여부
previewData  프리뷰 모드에서 사용되는 데이터.
 setPreviewData 함수를 통해 설정된 데이터가 이 속성을 통해 전달
locale  페이지에 설정된 현재 로캘(locale)을 나타냄.
 다국어 지원을 하는 경우 유용하게 사용
locales  사용 가능한 모든 로캘의 목록
defaultLocale  구성된 기본 로캘을 나타냄

 


  서버 사이드 렌더링 코드(getServerSideProps())

 

 

 

/pages/test.js

import Head from "next/head";
import Link from "next/link";

export async function getServerSideProps(context) {
  const s = context.query["s"]; // 아래 내용 참고

  const res = await fetch(
    `https://jsonplaceholder.typicode.com/comments?postId=${s}`
  );

  const numberData = await res.json();

  return { //정적생성과 같이 return 값 구조 같음
    props: {
      numberData,
      s,
    },
  };
}

export default function Test({ numberData, s }) {
  return (
    <>
      <Head>
        <title>테스트페이지</title>
      </Head>
      {numberData.map((number) => {
        return (
          <div
            key={number.id}
            style={{
              border: "1px solid #fff",
              marginBottom: "10px",
              width: "100%",
            }}
          >
            <h4>postid:{s}</h4>
            <h4>{number.name}</h4>
            <div>{number.email}</div>
            <div>{number.body}</div>
          </div>
        );
      })}
      <Link href={"/"}>뒤로가기</Link>
    </>
  );
}

 

 

1. context  속성 : 페이지에 대한 요청을 처리하는 데 필요한 여러 가지 데이터를 포함

params 동적 라우팅을 사용하는 페이지의 경우 현재 페이지에 대한 경로 매개변수(route parameters)를 포함
ex) [id].js
각 데이터를 매핑해서 id값을 추출해서 params에 등록해준다 (params: { id: 값 })
req HTTP 요청 객체로, 요청에 대한 세부 정보(예: 헤더, 요청 경로 등)를 포함
res HTTP 응답 객체로, 응답을 수정할 수 있는 방법을 제공
query URL 쿼리 문자열이 파싱된 객체 ex) ?s=1    ,  context.query{ s : '1' }
preview 페이지가 프리뷰 모드(preview mode)에서 렌더링되고 있는지 여부
previewData 프리뷰 모드에서 사용되는 데이터.
setPreviewData 함수를 통해 설정된 데이터가 이 속성을 통해 전달
locale 페이지에 설정된 현재 로캘(locale)을 나타냄.
다국어 지원을 하는 경우 유용하게 사용
locales 사용 가능한 모든 로캘의 목록
defaultLocale 구성된 기본 로캘을 나타냄

 

728x90
반응형

댓글