실전 웹 어플리케이션 개발 3장 Next 정리

이수빈·2023년 10월 19일
0

Next.js

목록 보기
7/15
post-thumbnail

Next.js 렌더링 방법

  • SSG,SSR,CSR,ISR 존재함

  • 파일 내부에서 컴포넌트 외 구현하는 함수나 해당 반환값에 따라 렌더링 방법이 달라짐. 각 페이지들이 어떤 타입을 설정 돼 있는지 빌듯시 결과로 확인 할 수 있음.

  • 렌더링방식을 결정하는 주요한 요소는 데이터 취득 함수임.

종류데이터취득시 사용함수데이터 취득시점비고
SSGgetStaticProps빌드시데이터 취득 함수를 사용하지 않는 경우도 SSG임
SSRgetServerSideProps사용자요청시getInitialProps를 사용해도 SSR
ISRrevalidate를 반환하는 getStaticProps빌드시배포후에도 백그라운드 빌드진행
CSRuseEffect, useSWR...사용자요청시(브라우저)ISR/SSG/SSR와 동시사용가능

SSG를 통한 페이지 구현

  • 페이지는 getStaticProps가 반환한 props를 받을 수 있다.(없을수도 있음)

  • getStaticProps는 비동기함수로 async와 함께 정의해야함.

  • 인수에는 context가 존재함. => 빌드시에 사용할 수 있는 데이터가 포함됨.

import { GetStaticProps, NextPage, NextPageContext } from "next";
import Head from "next/head";

// 페이지 컴포넌트인 props의 타입 정의
type SSGProps = {
  message: string;
};

// SSG는 getStaticProps가 반환한 props를 받을 수 있다
// NextPage<SSGProps>는 Message: string 만을 받아 생성된 페이지 타입
// Next.js의 페이지 컴포넌트나 함수 타입은 https://nextjs.org/learn/excel/typescript/nextjs-types도 참고한다
const SSG: NextPage<SSGProps> = (props) => {
  const { message } = props;

  return (
    <div>
      <Head>
        <title>Static Site Generation</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <main>
        <p>이 페이지는 정적 사이트 생성을 통해 빌드 시 생성된 페이지입니다.</p>
        <p>{message}</p>
      </main>
    </div>
  );
};

// getStaticProps는 빌드에 실행된다
// GetStaticProps<SSGProps>는 SSGProps인수로 받는 getSTaticProps 타입
export const getStaticProps: GetStaticProps<SSGProps> = async (context) => {
  const timestamp = new Date().toLocaleString();
  const message = `${timestamp}에 getStaticProps가 실행되었습니다`;
  console.log(message);
  return {
    // 여기에서 반환한 props를 기반으로 페이지 컴포넌트를 그린다
    props: {
      message,
    },
  };
};

export default SSG;

getStaticPaths을 이용한 여러 페이지의 SSG

  • 데이터가 다른 여러개의 페이지를 만들 때 동적라우팅 기능을 사용가능함.

  • [id].tsx와 같이 대괄호로 감싼 파일이거나

  • getStaticProps에 맞춰 getStaticPaths를 사용할 수 있음

  • getStaticPaths는 getStaticProps 실행전에 호출되는 함수로, 생성팔 페이지의 경로 파라미터의 조합

  • 아래 코드에서는 id가 1,2,3인 경로파라미터를 반환함 => /post/1, /post/2, /post/3 이렇게 생성함.

  • fallback을 false로 반환하면 path에 주어지지 않은 경로에 대해서는 404를 뱉는다. fallback true라면, 최초요청과 그 뒤 요청에서 동작방식이 달라짐.

  • 12버전에서의 Image 컴포넌트는 next/legacy/image로 사용가능. (13버전 사용권장) => span으로 감싸서 image position을 결정하는 방식


// 타입을 사용하기 위한 임포트
import { GetStaticPaths, GetStaticProps, NextPage } from 'next'
import Head from 'next/head'
import { useRouter } from 'next/router' // next/router에서 useRouter라는 훅을 삽입한다
import { ParsedUrlQuery } from 'querystring'

type PostProps = {
  id: string
}

const Post: NextPage<PostProps> = (props) => {
  const { id } = props
  const router = useRouter()

  if (router.isFallback) {
    // 폴백 페이지용 표시를 반환한다
    return <div>Loading...</div>
  }

  return (
    <div>
      <Head>
        <title>Create Next App</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <main> <p> 이 페이지는 정적 사이트 생성을 통해 빌드 시 생성된 페이지입니다.
        </p>
        <p>{`/posts/${id}에 대응하는 페이지입니다`}</p>
      </main>
    </div>
  )
}

// getStaticPaths는 생성한 페이지의 경로 파라미터의 조합을 반환한다
// 이 파일은 pages/posts/[id].tsx이므로, 경로 파라미터로서 id의 값을 반환해야 한다
export const getStaticPaths: GetStaticPaths = async () => {
  // 각 페이지의 경로 파라미터를 모은 것
  const paths = [
    {
      params: {
        id: '1',
      },
    },
    {
      params: {
        id: '2',
      },
    },
    {
      params: {
        id: '3',
      },
    },
  ]

  // fallback을 false로 설정하면, paths에 정의된 페이지 아래는 404를 표시한다
  return { paths, fallback: false }
}

// 파라미터 타입을 정의
interface PostParams extends ParsedUrlQuery {
  id: string
}

// getStaticPaths 실행 후에 각 경로에 대해 getStaticProps가 실행된다
export const getStaticProps: GetStaticProps<PostProps, PostParams> = async (context) => {
  return {
    props: {
      id: context.params!['id'],
    },
  }
}

export default Post

SSR, ISR을 통한 페이지 구현

  • SSR : getSeverSideProps 호출

  • ISR : revalidate를 반호나하는 getStaticProps를 호출

  • 가장 처음으로 페이지에 접근한 경우에는 SSG의 경우와 마찬가지로 fallback페이지를 표시함. 이후에 요청에서는 revalidate 지정한 시간내에는 같은 페이지를 반환함.

  • 유효기간 이후에는 현재 저장되있는 페이지에 getStaticProps를 재 호출해 새로운 캐시로 저장함.

import { GetStaticPaths, NextPage, GetStaticProps } from 'next'
import Head from 'next/head'
import { useRouter } from 'next/router'

type ISRProps = {
  message: string
}

// ISRProps를 받는 NextPage(페이지) 타입
const ISR: NextPage<ISRProps> = (props) => {
  const { message } = props

  const router = useRouter()

  if (router.isFallback) {
    // 폴백용 페이지를 반환한다
    return <div>Loading...</div>
  }

  return (
    <div>
      <Head>
        <title>Create Next App</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <main>
        <p>이 페이지는 ISR을 통해 빌드 시 생성된 페이지입니다.</p>
        <p>{message}</p>
      </main>
    </div>
  )
}

export const getStaticProps: GetStaticProps<ISRProps> = async (context) => {
  const timestamp = new Date().toLocaleString()
  const message = `${timestamp}에 이 페이지의 getStaticProps가 실행되었습니다`

  return {
    props: {
      message,
    },
    // 페이지의 유효 기간을 초단위로 지정한다
    revalidate: 60,
  }
}

export default ISR

Next.js의 기능

  • Link 컴포넌트는 CSR방식으로 동작함. 새로운 페이지를 그리기 위한 데이터는 미리 비동기 방식으로 얻는다.

  • a태그를 Link태그로 감싸거나 버튼을 감싸는 형태로 사용

  • router.push를 통해 이동가능함 + 쿼리스트링 지정가능

Image 컴포넌트

  • img태그가 아니라 Image 컴포넌트를 사용해서 이미지를 읽을 때 서버사이드에서 이미지를 최적화함.

  • Image 컴포넌트에 width, height를 전달하지 않으면 에러 발생함.

  • img 태그와 마찬가지로 src에 이미지 경로를 전달하는데, 로컬 이미지에 대해서는 import한 이미지파일을 src에 부여가능(이때 width, height 생략가능함)

  • 브라우저의 정보를 기반으로 최적화환 이미지를 제공함. => Webp대응 브러우저에서는 WebP형식을 제공하거나, 브라우저 화면 크기에 맞춰 적절한 이미지를 제공하기도 함.

  • prop을 받을 수 있음

  • layout을 조절하는 prop, 이미지 로딩중에 표시할 컨텐츠인 placeholder등이 존재

  • 외부 이미지 같은 경우, next.config.js domains에 최적화를 허가하는 이미지의 도메인을 추가하거나, Image 컴포넌트의 unoptimzed에 true를 전달해 최적화를 무효화해야함.

  • Next Image 컴포넌트는 WebP 타입의 이미지를 다운로드함. => 일반적인 jpg보다 용량이 훨씬 작다.

  • Next Image를 사용하면 서버에서 자동으로 최적화를 진행해줌, quality 속성을 통해 얼마나 최적화 할지도 결정 할 수 있음. + lazy loading도 자동으로 설정됨.

  • PlaceHolder blur 옵션을 설정하면 사진이 다운로드 되는 동안 블러이미지가 자동으로 적용됨.

  • Next에서 최적화를 가능한 이유는 => 파일을 static하게 import했기 때문 => 빌드시에 미리 width height 값을 알 수 있다.

  • 만약 외부링크로 가져올때는 width, height를 미리 알 수 없음 => fill 이라는 속성을 사용해서 이를 해결가능함.

  • 이 경우 부모컴포넌트의 사이즈에 따라 Image Size가 결정됨, object fit속성을 같이 사용한다.

  • 외부링크 자체를 사용 할 수 없는경우 => next.config 설정을 변경해주어야 한다.

NextScript

  • 외부 API를 이용가능하게 해주는 컴포넌트임

  • https://nextjs.org/docs/pages/api-reference/components/script

  • onLoad, onReady와 같이 script가 성공적으로 호출되었을 때 실행가능하게 해주는 callback prop들이 존재함.

  • onLoad => 스크립트가 처음 불러와 졌을때만 실행됨, onReady => script가 성공적으로 실행되었을때 실행됨.

  • Strategy라는 속성존재 => loading 하는방식을 정의함.

  • afterInteractive(default) : 페이지가 hydration이 성공하자마자 script를 로드함.

  • beforeInteractive : 페이지 하이드레이션 전에 script를 가져옴. 페이지 하위의 다큐먼트 파일 즉 전역적으로 사용할 때 사용을 권장.

  • lazyOnload : script 필요시에 로딩함.

API 라우터 정의

  • pages/api 아래에 놓인 파일에서는 API(JSON 기반의 Web API) 를 정의함.

  • 빌드시에는 이 API를 사용할 수 없음(getStaticPaths, getStaticProps로부터 호출 불가)

import type { NextApiRequest, NextApiResponse } from 'next'

type HelloResponse = {
  name: string
}

// /api/hello에서 호출되었을 때의 API 동작을 구현한다
export default (req: NextApiRequest, res: NextApiResponse<HelloResponse>) => {
  // 상태 200으로 {"name": "John Doe"}를 반환한다
  res.status(200).json({ name: 'John Doe' })
}

환경변수

  • .env 파일 내부적으로 처리가능 => .env, .env.local, .env.환경명,.env.{환경명} , .env.{환경명}.local

  • local이 붙은것은 .gitignore에 추가되는 것을 의도한 것으로 api 키 등 공개하고 싶지 않은 값을 저장하기 위해 사용함.

  • .env.development , .env.development.local은 개발환경의 환경변수로 사용함.

  • .env.production, .env.production.local은 프로덕션 환경에서의 환경변수로 사용함.

  • 로딩된 환경변수는 서버사이드에서 실행하는 처리에 참조 할 수 있음. 클라이언트 사이드에서도 접근 하고 싶은 값에는 NEXTPUBLIC 을 붙힙니다.

  
  import { NextPage, GetStaticProps } from 'next'
import Head from 'next/head'

const EnvSample: NextPage = (props) => {
  // 서버 사이드에서 그릴 때는 'test1'라 표시되고, 클라이언트 사이드에서 다시 그릴 때는 undefined로 표시된다
  console.log('process.env.TEST', process.env.TEST)
  // 'test2'라 표시된다
  console.log('process.env.NEXT_PUBLIC_TEST', process.env.NEXT_PUBLIC_TEST)

  return (
    <div>
      <Head>
        <title>Create Next App</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <main>
        {/* 서버 사이드에서 그릴 때는 'test1'이라 표시되고, 클라이언트 사이드에서 다시 그릴 때는 아무것도 표시되지 않는다 */}
        <p>{process.env.TEST}</p>
        {/* test2가 표시된다 */}
        <p>{process.env.NEXT_PUBLIC_TEST}</p>
      </main>
    </div>
  )
}

// getStaticProps는 항상 서버 사이드에서 실행되므로, 모든 환경 변수를 참조할 수 있다
export const getStaticProps: GetStaticProps = async (context) => {
  // 'test1'가 표시된다
  console.log('process.env.TEST', process.env.TEST)
  // 'test2'가 표시된다
  console.log('process.env.NEXT_PUBLIC_TEST', process.env.NEXT_PUBLIC_TEST)

  return {
    props: {

    },
  }
}

export default EnvSample
profile
응애 나 애기 개발자

0개의 댓글