[Next.js] 프리랜더링

iberis2·2023년 8월 3일
0

NextJS

목록 보기
5/9
post-thumbnail

프리 렌더링(Pre-rendering)


프리렌더링 : 웹 브라우저가 페이지를 로딩하기 이전에 렌더링하는 것

  • 정적 생성(Static Generation)
  • 서버사이드 렌더링(Server-side Rendering)으로 나뉜다.

Next.js에서는 기본적으로 모든 페이지를 정적 생성한다.

프리 렌더링 장점

① 초기 로딩이 빨라진다
HTML이 렌더링 된 상태로 제공되므로 자바스크립트를 로딩해서 리액트가 완전히 실행될 때까지 기다리지 않아도 화면을 볼 수 있다.

페이지의 html 코드를 볼 수 있는 단축키

  • 맥 : option + command + U
  • 윈도우 : Ctrl + U

자바스크립트 사용중지 설정

  • F12 → Settings → Preference → Debugger

    자바스크립트 사용 중지 후 화면에 접속했을 때
  • CSR 페이지 : 텅 빈 흰 화면
  • 프리렌더링 된 페이지 : 뼈대가 되는 HTML이 그려진 화면(동적 작용 CSS 등은 X) 이 나타난다
  • CSR 페이지 : 텅 빈 HTML 파일 불러옴 → 자바스크립트를 불러와서 렌더링하며 화면을 그려줌

    ▲ 리액트로 만든 CSR 페이지의 html 파일 <body><div id="root"> 태그만 있다
    - 자바스크립트를 불러오기 전까지 빈 흰색 화면만 보인다.

  • 프리렌더링 된 페이지 : 렌더링 된 HTML 파일을 불러 옴 → 자바스크립트 불러와서 연결 시킴 (Hydration)

    Hydration: 렌더링 된 HTML 과 리액트의 데이터를 연결하는 것

▲ Next.js로 만든 프리렌더링 된 페이지의 html 파일 <body> 에 모든 내용이 들어있다

  • 자바스크립트를 불러오기 전에도 화면에 뼈대가 되는 HTML 내용이 전부 들어있다. ( 동적으로 반응하지는 X)

② 검색 엔진 최적화가 된다

정적 생성(Static Generation)

: 프로젝트를 빌드하는 시점에 미리 HTML을 렌더링하는 것

  • 데이터가 자주 변경되지 않을 때 사용
  • 퀘스트가 들어올 때마다 매번 렌더링을 하는 서버사이드 렌더링보다 미리 렌더링을 해서 저장해 둔 것을 보내 주는 정적 생성 방식이 훨씬 빠르다

기본적으로 Next.js에서는 모든 페이지를 정적 생성한다.

// /pages/setting.js

import { useTheme } from '@/lib/ThemeContext'
import Dropdown from '@/components/Dropdown'
import styles from '@/styles/Setting.module.css'

export default function Setting() {
  const { theme, setTheme } = useTheme()

  return (
    <div>
      <h1 className={styles.title}>설정</h1>
      <section className={styles.section}>
        <h2 className={styles.sectionTitle}>테마 설정</h2>
        <Dropdown
          className={styles.input}
          name='theme'
          value={theme}
          onChange={(name, value) => setTheme(value)}
          options={[
            { label: '라이트', value: 'light' },
            { label: '다크', value: 'dark' },
          ]}
        />
      </section>
    </div>
  )
}

따로 받아오는 데이터가 없는 setting 페이지는 정적 생성된 html 파일이 넘어오게 된다.

export getStaticProps() 함수

정적 생성할 때 필요한 데이터를 api로 받아와야 하는 경우 getStaticProps() 함수 안에서 요청하고 데이터를 받아온다. 받은 데이터를 객체의 props 프로퍼티로 리턴하면, 컴포넌트의 props 로 받아서 사용할 수 있다.

import ProductList from '@/components/ProductList'
import SearchForm from '@/components/SearchForm'
import { getDatas } from '@/lib/apis'
import styles from '@/styles/Home.module.css'

// getStaticProps() 안에서 axios 요청
export const getStaticProps = async () => {
  const res = await axios.get('/products')
  const products = res.data.results ?? []
  
  return { props: { products } } // props 객체로 products 를 전달
}

export default function Home({ products }) {
  return (
    <>
      <SearchForm />
      <ProductList className={styles.products} products={products} />
    </>
  )
}

export getStaticPaths() 함수

다이나믹 라우팅 (ex: /pages/products/:id )을 하는 페이지를 정적 생성을 할 때에는 어떤 페이지를 정적 생성할지 지정해줘야 한다. getStaticPaths() 함수를 구현하고 export해서 지정한다.

getStaticPaths() 함수에서는 리턴 값으로 객체를 리턴하는데, paths 라는 배열에서 각 페이지에 해당하는 정보를 넘겨줄 수 있다.

  • 예를 들어서 id 값이 '1'인 페이지를 정적 생성하려면 { params: { id: '1' } }과 같이 쓸 수 있다.

  • 이 때 숫자1가 아닌 문자열 '1' 임을 주의해야 한다

그리고 fallback 이라는 속성을 사용해서 정적 생성되지 않은 페이지를 처리해 줄 것인지 지정할 수 있다.

  • fallback: true 이면 생성되지 않은 페이지로 접속했을 때 getStaticProps() 함수를 실행해 페이지를 만들어서 보여준다.
export const getStaticPaths = async () => {
  return {
    paths: [ // 1 페이지와 2 페이지를 정적 생성한다
      { params: { id: '1' }},
      { params: { id: '2' }},
    ],
    fallback: true, // 생성되지 않은 페이지로 접속하면 getStaticProps()를 실행해서 페이지를 만든다
  };
}

getStaticProps() 함수context 파라미터를 사용해 필요한 params (context.params) 값이나 쿼리스트링(context.query) 값을 참조할 수 있다.

export const getStaticProps = async (context) => {
  const { id } = context.params; // useRouter() 대신 사용
  
  // 쿼리 스트링(/search?q=맨투맨)인 경우 
  // const { q } = context.query; // q는 맨투맨을 참조한다

  let product;

  try {
    const res = await axios(`/products/${id}`);
    product = res.data;
  } catch { 
  // 데이터가 존재하지 않을 때의 예외 처리 → `/pages/404.js` 페이지로 이동 한다
    return { notFound: true };
  }

  return { props: { product }}; // product 데이터를 컴포넌트의 props로 내려준다.
}

getStaticPaths() 의 리턴 값 중 fallback: true라고 지정했을 때,

  • 필요한 데이터가 존재하지 않은 경우에 대한 예외처리로 { notFound: true } 를 리턴하면 데이터를 찾을 수 없을 때 404 페이지로 이동시킬 수 있다.
  • getStaticProps() 를 실행하는 동안 보여 줄 로딩 페이지는 data를 props를 받는 페이지 컴포넌트에서 필요한 데이터가 존재하지 않을 때 (ex: if(!props)) 를 처리해 주면 된다.
export default function Product({ product }) {
  
  if (!product) { // getStaticProps() 를 실행하는 동안 product 데이터가 아직 오지 않았을 때
    return <>로딩 중 ...</>
  }
  
  return <>상품 이름: {product.name}</>;
}

SSR 서버 사이드 렌더링

: Next.js 서버에 리퀘스트가 도착할 때마다 페이지를 렌더링해서 보내주는 방식

  • 데이터가 자주 업데이트 되거나 항상 최신 데이터를 보여줘야할 때 사용
  • 리퀘스트의 데이터를 사용해야 하는 경우 (예: 헤더, 쿼리스트링, 쿠키 등) 사용

getServerSideProps()

getStaticProps() 대신 getServerSideProps() 함수를 구현하고, export 한다.

  • 리턴 값으로는 정적 생성때와 마찬가지로 props 프로퍼티로 Props 객체를 넘겨주고, 페이지 컴포넌트에서 받아서 사용한다.
  • 정적 생성과 동시에 할 수 없으므로 getStaticPaths() 와 함께 사용할 수 없다
export const getServerSideProps = async () => {
  const res = await axios('/products/');
  const products = res.data;

  return { props: { products }};
}

export default function Home({ products }) {
  return (
    <ProductList products={products} />
  );
}

참고 : 🔗코드잇 Next.js로 웹사이트 만들기

profile
React, Next.js, TypeScript 로 개발 중인 프론트엔드 개발자

0개의 댓글