Next.js 정리

heyhey·2023년 6월 8일
0

frontend

목록 보기
8/14

현재 프론트엔드 엔지니어로, React 만 사용하여도 충분하다고 생각했었습니다.
하지만 날이 갈수록 프론트엔드로써 Next는 필수가 되어가고 있고, 선택이 아닌 필수라는 말이 많습니다.
Next를 사용해보며 왜 이렇게 대세가 되었는지 알아보겠습니다.

Next 를 사용하는 이유

기존에 React는 Client-side Rendering입니다. Vue, Angular 또한 CSR 방식으로 이 방법이 대세였습니다.

하지만 지금은 다시 Server-side Rendering 이 다시 유행한다고 합니다.

Server Side Rendering

서버에서 html을 미리 만들어 받아오는 방식입니다.

  • CSR
    • 이쁘고 부드러운 사이트를 만들 수 있어 사용자 경험에는 좋습니다.
    • 초기 로딩 속도가 느립니다.
    • 검색 엔진 크롤러가 페이지의 콘텐츠를 인식하기 어렵습니다.
  • SSR
    • 첫페이지를 빠르게 불러올 수 있습니다.
    • 서버에서 완성된 html을 제공하기 때문에 콘텐츠를 인식하기 쉬워 구글 검색 노출도가 높아집니다.

SSR 을 위해서는 우리가 React에서 밥먹듯이 사용했던, state와 useEffect 등의 사용을 지양하는 것을 권장합니다.
상태관리를 하기에는 좋지만, 그 과정에서는 성능을 저하시킬 수 있기 때문입니다.

부가기능

원초적 목적은 SSR 이지만 부가기능들도 많습니다.

  • routing
  • 서버 api 기능 -> db 연결
  • 캐싱 기능
  • 이미지 최적화,

시작하기

  • Next 13 버전 사용
  • Node 는 18버전 이상을 사용합니다.

npx create-next-app@latest
를 입력하게 되면, 프로젝트이름, ts 사용 등 여러 설정을 확인해줍니다.

npm run dev 를 통해서 실행할 수 있습니다.

  • page.tsx
    폴더 구조를 보면 page.tsx가 메인 화면 입니다.

routing 도 자동으로 되어있습니다.
원하는 폴더를 만들고, 그 안에서 page.tsx 를 만들면 알아서 라우팅 기능이 가능합니다 (신세계다..)

필요한 컴포넌트는 page.tsx 라는 이름이 아니게 만들면, 불러와서 사용할 수 있습니다.

  • layout.tsx
    메인 페이지를 감싸는 용도의 페이지입니다.

  • next.config.js
    nextjs 설정 파일입니다.
    이 파일에서 설정할게 많을 예정입니다.

<Image/>

성능과 속도가 중요할 때는 <img/> 가 아닌 <Image/> 태그를 사용합니다.
<Image/> 태그는 다음 기능을 갖습니다.

  • 이미지 렌더링을 최적화 하기 위해, 자동으로 용량을 줄이고, 필요한 장면만 로드하고, 화면 크기에 맞게 조정하는 등의 작업을 수행합니다.

  • lazy loading

    • 이미지를 스크롤하거나 해당 이미지가 화면에 표시될 때ㄷ까지 로드되지 않습니다. => 페이지에 빠르게 접근할 수 있게 합니다.
  • 반응형 이미지

    • 하나의 이미지 소스로 여러개의 크기의 이미지를 생성하고, 사용자의 장치와 화면 크기에 맞게 최적의 이미지를 제공합니다.
  • 이미지 캐싱

    • 이미지가 한번 로드되면, 이미지를 캐시하고 다음 요청에는 캐시된 이미지를 사용합니다.

이 태그는 몇가지 사용법이 있습니다.

  1. width 와 height 옵션을 적어줘야 합니다.
  2. 혹은 fill=true 를 넣고 div 태그의 사이즈를 조절해도 됩니다.
  3. public이나 내 프로젝트 이외의 사진을 사용하고 싶다(db 사진) 면, 세팅을 해줘야합니다.
    그래서 외부 사진은 그냥 <img/>태그를 쓰는게 편할 수도 있습니다.

next.config.js

/** @type {import('next').NextConfig} */
module.exports = {
  images: {
    remotePatterns: [
      {
        protocol: "https",
        hostname: "s3.amazonaws.com",
        port: "",
        pathname: "/my-bucket/**",
      },
    ],
  },
};

Client Component

컴포넌트를 만들 때 페이지 맨 위에 'use client' 라고 한줄만 적으면 그 아래의 모든 컴포넌트는 client component가 됩니다.

  • html에 JS 를 넣어서 useEffect, state 등의 기능이 사용 가능합니다.
  • 쓸데없는 JS로 인해 용량이 커지고, 로딩 속도가 느려집니다.
    • 그 중 hydration 이라는 과정이 있는데, 컴퓨터가 html을 읽고 리액트 문법을 적용하기 위해 과정이 필요합니다.
    • 그것이 페이지 로드속도 저하에 큰 영향을 미칩니다.

그래서 큰 페이지들은 포통 Server Component 로 만들고, JS 기능이 필요한 기능은 Client Component 로 만드는 것이 좋은 습관입니다.

Hook 은 client component 내에서만 사용가능합니다.
useEffect, useState , useRouter 등을 이용하기 위해서는 'use client' 를 이용해야 합니다.

api 만들기

pages 의 api 폴더 안에 원하는 이름의 폴더 안에 + index.ts 파일을 만들어 줍니다.

pages/api/articles/index

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  const db = (await connectDB).db("forum");
  if (req.method === "GET") {
    const list = await getList(db);
    return res.status(200).json(list);
  }
}

const getList = async (db: any) => {
  const list: {
    title: string;
    content: string;
    _id: string;
  }[] = await db.collection("post").find().toArray();

  return list || [];
};

이렇게 만들면 [GET]api/articles 로 요청을 보내게 되면, getList의 값이 보내집니다.

if (req.method === "POST") {
  const result = await db.collection("post").insertOne(req.body);
  return res.status(200).redirect("/articles");
}

이번엔 POST 요청으로 보내면, 글을 작성해줍니다.

SEO

client component를 이용해서 페이지를 만들게 되면 검색엔진 봇이 페이지를 수집하려고 방문하면 텅빈 html을 보게 됩니다.

검색노출이 중요한 페이지를 만들 때에는, client component로 만들고 버데이터를 가져오는 것이 추천되지 않습니다.
이럴 때에는 부모 server component에서 db 데이터를 가져온 다음 props로 전송하는 방법을 이용합시다.

정적 생성 VS SSR

두개의 차이가 헷갈릴 수 있습니다.
차이점은 언제 html 파일을 생성하는가 입니다.

[정적 생성]

  • 프로젝트가 빌드하는 시점에 html 파일들이 실행됩니다.

  • 모든 요청에 재사용됩니다.

  • 퍼포먼스 이유로, Next js 는 정적 생성을 권고합니다.

  • 정적 생성된 페이지들은 CDN에 캐시됩니다.

  • getStaticPropsgetStaticPaths 를 이용해서 사용가능합니다.

[서버사이드 렌더링]

  • 항상 최신 상태를 유지합니다.
  • getServerSideProps

유저가 요청하기 전에 페이지가 만들어도 상관없으면 ? => 정적생성
ex ) 도움말 리스트, 제품 목록, 마케팅 페이지, 블로그 페이지 ..

요청이 있을때마다 다시 그려야 한다면 => SSR

getServerSideProps

사용법에 대해서 알아보겠습니다. 바로 코드로 확인합니다.

const Post = ({item})=>{
  return (
    <>
      <Head>
        <title>{item.name}</title>
        <meta name="description" content={item.description}></meta>
      </Head>
      <Item>
        {item}
      </Item>
    <>
    )
}
export async function getServerSideProps(context){
  const id = context.params.id;
  const res = await Axios.get(apiURL)
  const data = res.data
  return {
    props:{
      item : data
    }
  }
}

item을 getServerSideProps 에서 받아와서 보내줍니다.
이 값을 title 과 meta 태그를 통해 보여지게 되면 검색엔진 최적화가 가능해집니다.

=> 공유를 하게 되면, 데이터가 보입니다.

환경변수

.env.development, .env.production 파일을 두개 만들어 줍니다.

name = DEV;
NEXT_PUBLIC_API_URL = "http....";
name = PROD;
NEXT_PUBLIC_API_URL = "http....";

사용법은 node.js 와 브라우저 환경에 따라 다릅니다.

  • node.js
    process.env.변수명

  • 브라우저
    process.env.NEXT_PUBLIC_변수명

const Home(){
  // 브라우저 환경이라서 언더바(_)가 들어감
  const API_URL = process.env.NEXT_PUBLIC_API_URL;
  ...
}

getServerSideProps는 브라우저 환경이 아니라, 서버에서 동작합니다.
window 같은걸 사용하면 에러가 납니다.

export async function getServerSideProps(context) {
  const id = context.params.id;
  const res = await Axios.get(apiURL);
  const data = res.data;

  return {
    props: {
      item: data,
      name: process.env.name,
    },
  };
}

getStaticProps

정적 생성은 빌드시에 html을 생성해서, 미리 렌더링된 html을 유저들에게 보내주게 됩니다.

getStaticPaths

동적 라우팅을 사용할 때, 어떤 페이지를 미리 Static으로 빌드할 지 정하는 api
= pages/[id].tsx 형태의 동적 라우팅 페이지 중, 빌드 시에 static하게 생성할 페이지를 정합니다.

export const getStaticProps = async () => {
  return {
    path: [
      { params: { id: "1" } },
      { params: { id: "2" } },
      { params: { id: "3" } },
    ],
    fallback: true,
  };
};

fallback

false

  • return 에서 리턴하지 않은 값을 404 페이지로 연결합니다.

true

  1. 사용자에게 fallback 페이지를 보여줍니다.
  2. 서버에서 static하게 페이지를 생성합니다.
  3. 해당 페이지를 사용자에게 보여줍니다.
  4. 다음부터 해당 페이지로 접속하는 사용자에게는 static한 페이지를 보여줍니다.

blocking

리턴하지 않은 페이지에 접속시

  1. 사용자에게 static한 페이지를 보여줍니다.
  2. 다음부터 해당 페이지로 접속하는 사용자에게는 static한 페이지를 보여줍니다.

즉 fallback 페이지가 없습니다.


정리

getServerSideProps

SSR 방식으로 서버 측에서만 실행되고, 브라우저에서 실행되지 않습니다.
페이지 요청시 마다 진행됩니다.
동적으로 데이터를 가져와 업데이트가 가능하다는 장점이 있습니다.

요청시 데이터를 가져와 페이지를 미리 렌더링해야 하는 경우에 사용합니다.
Next.js 는 정말 필요할떄만 사용하라고 합니다.

  • 사용자 대시보드는 사용자별 비공개 페이지므로 SEO와 관련이 없어서 미리 렌더링할 필요가 없습니다.
  • 데이터를 미리 가져올 필요가 없다면, CSR을 통해 데이터를 받아오는 것도 고려해볼만 합니다.

getStaticProps

SSR 방식으로 정적 페이지 생성 방식입니다.
빌드 단계에서만 데이터를 가져오고, JSON 으로 저장해 고정적으로 사용합니다.
페이지 요청 때마다 데이터를 가져오는 것이 아니라서 성능면에서 뛰어납니다.

  • SEO가 중요한 페이지에서 사용합니다.
  • 빌드 후에도 고정되는 내용을 보여주는 페이지에 사용됩니다.
    • 변하지 않는 공개적인 캐시 데이터를 가져올 필요가 있을 때

getStaticPaths

getStaticProps 와 함께 사용되며, 동적 라우팅이 필요할 때 사용합니다.

profile
주경야독

0개의 댓글