본문 바로가기
웹 프로그래밍/Next.js

[유데미 | winterlood 이정환] 프로젝트로 배우는 React.js & Next.js 마스터리 클래스 강의 내용 정리 (섹션 14: Next.js 렌더링 1 - SSR)

by 청량리 물냉면 2024. 1. 22.
반응형

섹션 14: Next.js 렌더링 1 - SSR

SSR(서버 사이드 렌더링) 이해하기

  • 첫 번째 렌더링: 리액트 컴포넌트와 같이 js로 작성된 페이지를 실제 html 코드로 변환하는 과정
  • 두 번째 렌더링: 변환된 html을 화면(브라우저)에 실제로 그리는 것

 

 js 코드와 html 요소들을 서로 연결함 👉 Hydration (수화)

  • 동작하지 않는 html 요소들에 js 코드를 연결시켜주는 과정
  • 이 과정을 거치면 버튼, 인풋 등 브라우저와 상호작용이 가능해진다.

 

SSR(서버 사이드 렌더링) 적용하기 1

pages > index.js

export default function Home({ name }) {
  return <div>{name}</div>;
}

// 해당 컴포넌트를 SSR 방식으로 동작하게 한다.
export const getServerSideProps = async () => {
  // SSR을 위해 서버측에서 페이지 컴포넌트에게 전달할 데이터를 설정하는 함수
  return {
    //반환값은 객체
    props: {
      //내부 값이 Home 컴포넌트에게 전달된다.
      name: "KOREA",
    }, //props의 값도 객체여야 함
  };
};

서버 측에서 먼저 렌더링한 뒤에 그 값을 이용해 화면을 렌더링한다.

 

서버 측에서 코드를 렌더링하기 때문에

  • `console.log()` 함수를 실행해도 브라우저에 값이 찍히지 않는다.(터미널에서는 출력값을 확인 가능)
  • `window.locaion`과 같이 윈도우 객체에 접근하려고 하면 에러가 발생한다. (`window`는 브라우저 관련 코드이고, node.js 환경에서는 존재하지 않는 값이기 때문) 👉 서버사이드에서 렌더링을 위해 클라이언트 코드에도 한 번은 접근하므로, 클라이언트 코드에도 `window` 사용 시 에러가 발생한다.
  • 클라이언트에서만 코드를 실행하려면, 브라우저에서 마운트 발생 시에만 실행되는 `useEffect` 훅을 사용해 주면 된다.

 

SSR(서버 사이드 렌더링) 적용하기 2

루트폴더 > api.js

import axios from "axios";

export async function fetchCountries() {
  try {
    //api: 비동기로 동작. 호출한다고 해서 바로 값이 response에 담기는 것이 아님
    //async: 내부에 await를 사용할 수 있게 됨
    //await: 비동기 코드를 기다렸다가 response에 넣어준다.
    const response = await axios.get("https://naras-api.vercel.app/all");

    return response.data;
  } catch (e) {
    //에러대응 코드
    return [];
  }
}

export async function fetchSearchResults(q) {
  try {
    const response = await axios.get(
      `https://naras-api.vercel.app/search?q=${q}`
    );

    return response.data;
  } catch (e) {
    return [];
  }
}

export async function fetchCountry(code) {
  try {
    const response = await axios.get(
      `https://naras-api.vercel.app/code/${code}`
    );

    return response.data;
  } catch (e) {
    return null;
  }
}

 

pages > index.js

 

import { fetchCountries } from "@/api";

export default function Home({ countries }) {
  return (
    <div>
      {countries.map((country) => (
        <div key={country.code}>{country.commonName}</div>
      ))}
    </div>
  );
}

// 해당 컴포넌트를 SSR 방식으로 동작하게 한다.
export const getServerSideProps = async () => {
  const countries = await fetchCountries();

  return {
    props: {
      countries,
    },
  };
};

서버 측에서 html로 렌더링한 뒤 브라우저에 보내준 모습

 

Search (쿼리 스트링 이용한 동적 라우팅 필요)

search 폴더 > index.js

import { fetchSearchResults } from "@/api";
import SubLayout from "@/components/SubLayout";

export default function Search({ countries }) {
  return (
    <div>
      {countries.map((country) => (
        <div key={country.code}>{country.commonName}</div>
      ))}
    </div>
  );
}

Search.Layout = SubLayout;

//쿼리를 이용한 동적 라우팅을 위해 context 이용
//context: 브라우저의 접속요청에 대한 정보들이 저장되어 있다.
export const getServerSideProps = async (context) => {
  // 1. 검색 결과 api 호출
  // 2. props 리턴

  // const q = context.query.q;
  const { q } = context.query;

  let countries = [];
  if (q) {
    countries = await fetchSearchResults(q);
  }

  return {
    props: { countries },
  };
};

 

Country (국가 코드 이용한 동적 라우팅 필요)

[code].js

import { fetchCountry } from "@/api";
import SubLayout from "@/components/SubLayout";
import { useRouter } from "next/router";

export default function Country({ country }) {
  //code를 클라이언트에서 사용하기(useRouter 훅)
  const router = useRouter();
  const { code } = router.query; //구조분해 할당

  return (
    <div>
      {country.commonName} {country.officialName}
    </div>
  );
}

Country.Layout = SubLayout; //SubLayout을 적용시켜준다.

//code를 서버에서 사용하기(context)
export const getServerSideProps = async (context) => {
  const { code } = context.params;

  let country = null;
  if (code) {
    country = await fetchCountry(code);
  }

  return {
    props: { country },
  };
};

 

 

 

 

 

출처

https://kmooc.udemy.com/course/react-next-master/learn/lecture/39610746

반응형