Nextjs 톺아보기

SOPT·2022년 12월 28일
0

web

목록 보기
2/7
post-thumbnail

✨ Nextjs




Nextjs 는 React 의 대표적인 프레임워크로 서버서이드 렌더링(Server-Side Rendering, SSR)을 대표적 기능으로 내세우는 것이 특징이다.
처음 접하는 사람들은 현재 사용하는 React에서 불편함을 느끼지 못하는 경우도 있고, 서버사이드렌더링 이 얼마나 유용한 기능인지 와닿지 않는 사람들도 있을 것이다.
따라서 해당 챕터에서는 Nextjs의 대표적인 특징인 SSR 과 이것이 어떤 이득을 주는지와
30기 앱잼 nori 에서 중점적으로 사용하고 공부했던 Next 에서의 라우팅 기능을 소개하고자 한다.




✨ Server-Side Rendering(SSR)


30기 앱잼 초창기때, 29기 앱잼 서비스인 북스테어즈 에서 서비스를 기존 React 에서 Next로 리팩터링 한다는 이야기를 들었다.
북스테어즈에서 리팩터링을 하는 이유, 많은 서비스, 블로그에서 기술하듯이 Next를 사용하는 가장 큰 이유는 SEO(Search Engine Optimization)를 위한 Server-Side Rendering(SSR)이 가능하기 때문이라고 한다.
이게 무슨 뜻일까? 예시를 통해 보도록 하자.



기존 React 에서는 Client-Side Rendering(CSR)을 한다.
CSR 에서는 위 그림처럼 웹사이트를 요청했을 때 빈 html을 가져온 후 script를 로딩하기 떄문에, 첫 로딩 시간도 오래걸리고 SEO에 취약하다는 단점이 있다.(html 자체는 비어있기 때문에!)
또한 네트워크가 연결이 되어있지 않거나 느린 경우에 서비스 이용자는 script가 로딩되기 전까지 빈 화면을 보게 되는 경우가 생기게 된다.



반면 Nextjs 는 pre-reloading 을 통해 미리 데이터가 렌더링된 페이지를 가져올 수 있게 해 준다.
이는 사용자에게 더 좋은 경험을 주고 검색 엔진에 잘 노출 될 수 있도록 해주는 SEO에서도 장점을 얻을 수 있다.(HTML이 비어있지 않기 때문에!)




✨ Next의 가장 중요한 기능 라우팅


지난 번 APP-JAM 에서 nori 서비스를 개발하며 가장 인상깊게 남았던 부분은
Header는 각각의 페이지로 이동하는, Community는 고유의 내용이 담겨있는 페이지로 이동해야 하는 기능을 구현하는 것과 SSR을 적용시키는 방법이었다.
기존의 React와 Next에서 제공하는 라우팅이 어떻게 다른지 비교하며 알아보자.

1. Next.js 의 라우팅(파일시스템 기반 라우팅) / 정적라우팅


기존의 React에서의 라우팅이라 함은 Router를 별도로 설치하여 Router 파일에 컴포넌트를 import 하고 pathname을 지정해주는 방식이다.

// 합동세미나 당시 React 로 구현한 Router.
import Home from 'pages/Home';
import Room from 'pages/Room';
import WishList from 'pages/WishList';
import React from 'react';
import Wish from 'pages/Wish';
import ScrollToTop from './ScrollToTop';
import { BrowserRouter, Route, Routes } from 'react-router-dom'; // 컴포넌트 import

function Router() {
  return (
    <BrowserRouter>
      <ScrollToTop />
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/wishlist" element={<WishList />} />
        <Route path="/wish/:id" element={<Wish />} />
        <Route path="/wish/room/:id" element={<Room />} />
        <Route path="/*" element={<p>Page Not Found</p>} />
      </Routes>
    </BrowserRouter>
  );
}

하지만 Next.js는 파일시스템 기반 라우팅 을 지원한다.
때문에 더 직관적인 라우팅과 컴포넌트 구분이 가능하다.

pages폴더
  • 최초 프로젝트를 생성하면 자동적으로 pages 라는 폴더가 생성된다.
  • pages 폴더 안에 컴포넌트를 생성 하면 자동으로 경로가 설정되게 된다.
  • .tsx(혹은 .jsx, js, ts) 파일을 생성 한 후 useRouterLink 컴포넌트를 이용하여 해당 파일의 이름으로 경로를 설정한다.
// /common/Header.tsx 의 Menu 컴포넌트 일부
  <Link href="/viewProduct">
    <StMenuBtn type="button" onClick={handleClickExcept}>
      상품보기
    </StMenuBtn>
  </Link>
  <Link href="/community">
    <StMenuBtn type="button" onClick={handleClickExcept}>
      커뮤니티
    </StMenuBtn>
정적 라우팅 path
  • Link 컴포넌트는 next/Link 모듈에서 불러와 사용 할 수 있으며 href 속성으로 이동할 경로를 지정한다.
  • 위 코드의 StMenuBtn 을 클릭하게 되면 Community 컴포넌트를 렌더링 하게 되고, 경로 또한 자동적으로 파일명인 /Community 가 된다.
  • 이처럼 파일명으로 직관적으로 라우팅을 할 수 있음으로써 컴포넌트의 이름과 path의 이름을 통일하여 더 직관적인 컴포넌트 관리가 가능하다.
  • 또한 Link 컴포넌트는 브라우저의 History API를 지원하여 뒤로가기를 하더라도 이전에 렌더링한 페이지를 불러온다. 따라서 새 페이지를 불러오기 위한 요청을 하지 않아도 되며, 이전 페이지를 다시 컴파일할 필요가 없다는 장점이 있다.



2. 동적라우팅



Next.js 에서는 지정된 주소로의 정적 라우팅 뿐 만 아니라, 동적인 주소로의 라우팅도 가능한데

동적라우팅 파일구조
  • 동적 라우팅을 사용하기 위해서는 폴더 구조를 조금 수정을 해야 한다.
  • 위 사진의 community 폴더 안의 index.tsx 는 path가 /community 인 파일이다. 이렇게 해당하는 pathname 안에 있는 index 파일은 폴더 이름을 path로 가진다.
  • 다음으로 대괄호 []로 파일명을 감싸면 해당 페이지는 동적으로 경로가 지정되는 페이지가 된다.
  • 이제 동적 페이지가 존재하는 경로에 임의의 주소를 대입하면 대입한 주소를 쿼리명으로 갖는 페이지로 이동 할 수 있다.
  <StMainInfo
    onClick={() => Router.push({ pathname: `/community/${id}` })}
  >
    <h1>{title}</h1>
    <p>{content}</p>
  </StMainInfo>

위 코드는 {title}{contnet}를 클릭하면 해당 {id}값을 가지는 path로 이동하게 되는 기능을 구현한 코드이다.
여기서 {id} 는 API 에서 가져오는 각 게시글의 id 값이다.

동적라우팅 path

  • 동적 라우팅을 사용할떄는 하나의 주의사항이 있는데, 한 동적 경로에는 한 개의 동적 페이지만이 존재 할 수 있다.
/.next
/pages
  ㄴ-- index.jsx
  ㄴ-- /community
         ㄴ-- [cid].jsx
         ㄴ-- [name].jsx -> Error!
/public
/styles



Next v13의 등장

지난 10/26에 Next.js 13버전을 발표했다.

이 글을 통해 어떤 부분이 달라졌고, 내가 배포한 nori 에서 변경해야 할 부분을 먼저 점검해보고자 한다.
공식문서를 참고하였다.

👇 최신 버전을 다운로드 하고자 하면 아래의 명령을 수행하면 된다.

npm i next@latest react@latest react-dom@latest eslint-config-next@latest

✨ app/ Directory (beta)

✨ 라우팅을 비교해보자

Next.js에서 가장 사랑받는 기능 중 하나는 파일 시스템 라우터이다. 즉, 폴더 안에 파일을 옮겨놓기만 애플리케이션에서 즉시 경로를 생성할 수 있다.


위의 폴더 구조를 따르게 되면 https://www.with-nori.com/write, https://www.with-nori.com/comunity로 경로가 생성된다.

👇 일단, app/ 의 구조로 바꾸기 위해서는 next.config.js를 수정해야 한다.

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  swcMinify: true,
  // 추가
  experimental: { appDir: true },
};

module.exports = nextConfig;

✨ Layouts

주요 업데이트 내용을 살펴보자

하지만 이제는 pages가 아닌 app에 page와 layout을 넣어야 한다.

//app/layout.tsx

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html>
      <head></head>
      <body>{children}</body>
    </html>
  );
}
// app/page.tsx

export default function page() {
  return <div>메인 페이지 입니다</div>;
}

해당 페이지와 레이아웃을 적용한 결과이다.

여기서 RootLayout에 네비게이션바를 넣어주면..!

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html>
      <head></head>
      <body>
        <nav>네비게이션 바</nav>
        {children}
      </body>
    </html>
  );
}

아래처럼 네비게이션바가 defalut로 설정된 것을 확인할 수 있다💡

✨ Data Fetching

지금까지 next에서 SSR을 적용할 때는 getServerSideProps, getStaticProps를 사용하였다.

import { GetServerSideProps } from "next";

export default function page() {
  return <div>메인 페이지 입니다</div>;
}
export const getServerSideProps: GetServerSideProps = async (context) => {
  const res = await fetch("https://dummyjson.com/todos/1");
  const data = await res.json();

  return {
    props: {
      data,
    },
  };
};

하지만, app에서는 해당 메소드를 지원하지 않는다는 것을 확인할 수 있다.

그렇다면 어떻게 데이터를 불러와야 할까?

import { use } from "react";

export default function page() {
  const data = use(getData());
  return (
    <div>
      메인 페이지 입니다<p>{data.todo}</p>
    </div>
  );
}
export const getData = async () => {
  const res = await fetch("https://dummyjson.com/todos/1");
  const data = await res.json();

  return data;
};

위와 같이 getData라는 함수를 선언한 뒤에, use() 안에 넣어주기만 하면 요청이 이루어진다.


❗️❗️❗️여기서❗️❗️❗️

fetch 구문의 URL 뒤에 { cache: '' } 자리에 무엇이 들어가냐에 따라 기존의 getServerSideProps, getStaticProps와 유사한 기능을 구현하게 된다.

성공적으로 Data Fetching이 이루어진 것을 확인할 수 있다.

✨ next/Image

👇Image 컴포넌트를 통해서 이미지 파일을 넣을 수 있는데,

 <Image
          src={`https://nori-image.s3.ap-northeast-2.amazonaws.com/${image}`}
        ></Image>

Next.js 13에서는 아래의 두 가지가 업데이트되었다.

  • alt기본적으로 태그를 필요로 하는 접근성 향상
  • 이미지 로드가 느릴 경우에 기존의 레이아웃이 밀려나는 현상인 Layout Shift를 막기위해 자동으로 width height를 설정하여 최적화

✨ next/font

👇font도 Image와 마찬가지로 Layout Shift를 막고, 이제 구글 폰트가 내장되어진것이 크게 달라졌다!

yarn add @next/font

폰트를 설치하고, 원하는 구글 폰트를 불러와 className으로 적용시키면 된다.

import { Roboto_Mono } from "@next/font/google";

const roboto = Roboto_Mono({
  weight: "400",
});
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html className={roboto.className}>
      <head></head>
      <body>
        <nav>네비게이션 바</nav>
        {children}
      </body>
    </html>
  );
}

아래처럼 글꼴이 바뀌어 진 것을 확인할 수 있다.

기존 Next.js 12에서는 태그 이후에 자식으로 반드시 태그를 필요로 하였다.

<Link href={`/write/${cid}`}>
    <li>
        <a>수정하기</a>
    </li>
</Link>

하지만, Next.js 13에서는 항상 를 렌더링 하기에 자식으로 태그를 가질 필요가 없어졌다.

<Link href={`/write/${cid}`}>
    <li>수정하기</li>
</Link>

글을 줄이며...

지난 앱잼에서 Next.js 를 사용할때 가장 중요하고 인상깊었던 기능인 라우팅 방법에 대해 다시 한 번 살펴보았다.
더불어, 최근 Next.js 는 13버전을 발표하면서 새로운 기능들이 추가되었다.

지난 앱잼에서 Next.js 를 사용할때 가장 중요하고 인상깊었던 기능인 라우팅 방법에 대해 다시 한 번 살펴보았다.
더불어, 최근 Next.js 는 13버전을 발표하면서 라우팅 방식의 변경 뿐 만 아니라 새로운 기능들이 추가되었다.

물론, react-router-dom의 업데이트 만큼 많은 부분이 바뀐 것은 아니었지만, Link태그나 이미지와 app/으로 페이지 이동을 구현하는 것은 재미있게 살펴보았다.

지금까지 살펴본 Next.js로 어떻게 해야 효과적으로 SSR을 적용시키면서 서비스를 운영해야 할 지에 대해서 꾸준한 고민과 공부가 필요하다고 느껴지는 시간이었다.



작성자

IN SOPT WEB, OB 홍서희
IN SOPT WEB, OB 김형겸

profile
IT 대학생벤처창업동아리 SOPT의 공식 블로그입니다.

0개의 댓글