Next.js 빨리 배우기

이 포스팅은 Next.js에서 제공하는 공식 튜토리얼을 기반으로 하였습니다.

빠르게 Next.js를 배워봅시다.

Next.js란?

기본적으로는 리액트를 기반으로 한 SPA를 빠르게 빌드할 수 있도록 도와주는 녀석입니다. 맨바닥부터 SPA의 환경을 하나씩 잡아가고 앱을 빌드하려면 높은 러닝커브가 필요한 반면 Next.js를 이용하면 빠르게 SPA를 빌드할 수 있습니다. 여러분이 앞으로 배워나갈 것은 client-side routing, page layout 정도 입니다. 기본적인 리액트 지식만 있다면 앞의 두가지만 배우고 매우 빠르게 여러분의 웹앱을 빌드할 수 있습니다. 그리고 Next.js의 가장 큰 장점 중 하나는 매우 간단하지만 커스터마이징이 매우 용이하다는 것입니다. 그리고 마지막으론 배포도 해볼 건데 매우 쉽습니다.

Next.js의 대표적 특징이자 장점

  • 기본적으로 서버사이드 렌더링을 제공함
    • 서버사이드 렌더링의 장점
      • 검색엔진 최적화
      • 초기 로딩 성능 개선
      • 그냥 검색엔진 최적화
      • SEO (Search Engine Optimization)
  • 더욱 빠른 페이지 로드를 위한 코드 스플리팅 자동화
  • HMR을 지원하는 웹팩 기반 환경
  • Express나 Node.js와 같은 http 서버와 함께 구현 가능
  • Babel, Webpack 설정 커스터마이징 가능

시작하기

먼저 빠르게 터미널을 켜줍시다 그리고 다음 명령어를 순서대로 칩니다.

mkdir next-project
cd next-project
yarn init -y
yarn add react react-dom next
code . (visual studio code를 IDE로 사용한다면 쳐주세요. 다른 IDE 쓰시면 알아서 프로젝트 찾아가시면 됩니다.)

Package.json 파일에 들어가서 다음 스크립트를 추가합니다.

"scripts": {
  "dev": "next",
  "build": "next build",
  "start": "next start"
}

인덱스 페이지 만들고 서버 구동해보기

메인 디렉토리에 pages라는 디렉토리를 만드세요. 이 디렉토리 이름은 고정으로 모든 페이지에 관련된 js는 pages라는 디렉토리에 넣어야 합니다.

그리고 index.js라는 파일을 하나 만드시고 아래 소스 복사 붙여넣기 하시면 됩니다. 아래 소스는 함수형 컴포넌트입니다. 혹시 잘 이해가 안되신다면 '함수형 컴포넌트' 구글에 쳐보시길 추천드립니다.

const Index = () => (
  <div>
    <p>index page</p>
  </div>
);

export default Index;

그럼 다음과 같은 상태가 될 것입니다.

Screen Shot 2019-08-13 at 7.21.00 PM.png

이제 터미널에 yarn dev를 쳐보세요. 그러면 서버가 켜집니다. 그럼 대략적으로 아래와 같은 화면이 보일겁니다.

Screen Shot 2019-08-13 at 7.21.36 PM.png

아주 쉽게 첫 서버구동에 성공했습니다.

페이지 이동 (Navigation) 만들기

이제 아주 빠르게 페이지를 이동하는 방법을 익혀봅시다.

이동할 페이지를 만들기 위해 pages 디렉토리 내부에 profile.js라는 파일을 만드시고 다음과 같은 내용을 작성해봅시다.

export default function Profile() {
  return (
    <div>
      <p>Hello, my name is jake seo. I use next.js</p>
    </div>
  );
}

그리고 이제 index.js를 수정해봅시다. 아래와 같이 작성하시면 됩니다.

import Link from "next/link";

const Index = () => (
  <div>
    <Link href="/profile">
      <a>Go Profile</a>
    </Link>
    <p>index page</p>
  </div>
);

export default Index;

여기서 이해해야 할 것은

  1. 페이지 이동을 위해 우리가 "next/link"에서 모듈을 불러와서 Link라는 태그를 작성하고 그 안에 a(anchor) 태그를 작성하였다는 것입니다.
  2. Link 태그의 속성에는 href를 넣어서 어디로 이동해야 파일이 있는지 명시해주었습니다.

    참고로 이렇게 네비게이션을 작성하면 뒤로가기도 잘 작동합니다.

공유 컴포넌트 사용하기

메인 디렉토리에 components라는 디렉토리를 만들고 Header.js라는 파일을 작성해줍시다. 내용은 다음과 같습니다.

import Link from 'next/link';

const linkStyle = {
  marginRight: 15
};

const Header = () => (
  <div>
    <Link href="/">
      <a style={linkStyle}>Home</a>
    </Link>
    <Link href="/profile">
      <a style={linkStyle}>Profile</a>
    </Link>
  </div>
);

export default Header;

Header.js를 작성했으면 index.js를 다음과 같이 수정해줍시다.

import Header from "../components/Header";

const Index = () => (
  <div>
    <Header />
    <p>index page</p>
  </div>
);

export default Index;

profile.js는 다음과 같이 수정해줍시다.

import Header from "../components/Header";

export default function Profile() {
  return (
    <div>
      <Header />
      <p>Hello, my name is jake seo. I use next.js</p>
    </div>
  );
}

그럼 다음과 같은 화면이 완성됩니다.

Screen Shot 2019-08-13 at 8.04.54 PM.png

짜잔~ 공유된 컴포넌트를 이용하여 네비게이션이 완성됐습니다.

레이아웃 만들기

공유 컴포넌트를 조금 발전시켜서 레이아웃을 만들 수 있습니다. components 디렉토리 밑에 Layout.js를 만들고 다음 코드를 작성해봅시다.

import Header from "./Header";

const layoutStyle = {
  margin: 20,
  padding: 20,
  border: "1px solid #DDD"
};

const Layout = props => (
  <div style={layoutStyle}>
    <Header />
    {props.children}
  </div>
);

export default Layout;

이제 만들어놓은 Layout.js를 사용하는 방식으로 index.js를 수정해봅시다.

import Layout from "../components/Layout";

const Index = () => (
  <Layout>
    <p>index page</p>
  </Layout>
);

export default Index;

profile.js도 수정해줍시다.

import Layout from "../components/Layout";

export default function Profile() {
  return (
    <Layout>
      <p>Hello, my name is jake seo. I use next.js</p>
    </Layout>
  );
}

수정이 끝나면 다음과 같은 화면을 볼 수 있을 것입니다.

Screen Shot 2019-08-13 at 8.48.59 PM.png

레이아웃이 적용되어 한층 업그레이드 되었습니다.

동적 페이지 만들기

이번에는 쿼리 스트링을 이용하여 동적 페이지를 만드는 방법을 알아보겠습니다.

쿼리스트링이란 우리가 페이지를 요청할 때 페이지명?a=b와 같은 형식으로 값을 넘겨주는 녀석을 말합니다.

먼저 index.js 파일을 수정해줍시다.

import Layout from "../components/Layout";
import Link from "next/link";

const ProfileLink = props => (
  <div>
    <Link href={`/profile?name=${props.name}`}>
      <a>Go to {props.name}'s profile</a>
    </Link>
  </div>
);

const Index = () => (
  <Layout>
    <h1>Friends List</h1>
    <ProfileLink name="jake" />
    <ProfileLink name="peter" />
    <ProfileLink name="yumi" />
  </Layout>
);

export default Index;

그리고 profile.js를 수정해줍시다.

import Layout from "../components/Layout";
import { useRouter } from "next/router";

export default function Profile() {
  const router = useRouter();

  return (
    <Layout>
      <p>Hello, my name is {router.query.name}. I use next.js</p>
    </Layout>
  );
}

이번 코드 수정에서 유의깊게 봐야 할 것은

  1. Link의 href에 ?name=이름 형태의 쿼리스트링을 넣어줬단 것이고,
  2. next/router에 존재하는 모듈 중 하나인 useRouter (훅스와 흡사합니다) 를 이용하여 쿼리에 담긴 문자열을 받았다는 것입니다.

이것만 기억하면 언제든 쿼리스트링으로 원하는 정보를 넘겨줄 수 있습니다.

깔끔한 URL로 동적 페이지 구성하기

이전에 사용했던 쿼리 스트링을 이용한 방법은 URL이 깔끔하지 않습니다. 그렇다면 URL을 깔끔하게 해서 동적 페이지를 구성하는 방법도 알아봅시다.

이번 방법은 조금 특이할 수 있기 때문에 잘 보셔야 합니다.

먼저 pages 디렉토리 내부에 p라는 디렉토리를 생성해주세요.
그리고 그 내부에 [profile].js 파일을 생성해주세요.

[profile].js의 내용은 다음과 같습니다.

import Layout from "../../components/Layout";
import { useRouter } from "next/router";

export default function Profile() {
  const router = useRouter();

  return (
    <Layout>
      <p>Hello, my name is {router.query.profile}. I use Next.js</p>
    </Layout>
  );
}

useRouter를 이용하여 쿼리 스트링을 가져오는 부분은 같습니다.

그 다음 index.js를 다음과 같이 수정해줍니다.

import Layout from "../components/Layout";
import Link from "next/link";

const ProfileLink = props => (
  <div>
    <Link href={`/p/[profile]`} as={`/p/${props.profile}`}>
      <a>Go to {props.profile}'s profile</a>
    </Link>
  </div>
);

const Index = () => (
  <Layout>
    <h1>Friends List</h1>
    <ProfileLink profile="Jake" />
    <ProfileLink profile="Peter" />
    <ProfileLink profile="Yumi" />
  </Layout>
);

export default Index;

여기서 유의깊게 봐야할 것은 hrefas입니다.

href는 실제 이동할 경로 [profile].js를 의미합니다.
as는 우리 URL에 어떻게 보일지를 결정합니다. 여기서는 /p/${props.profile}로 각 /p/이름 으로 URL창에 나타날것입니다.

결과는 다음과 같습니다.

Screen Shot 2019-08-13 at 9.18.27 PM.png

Screen Shot 2019-08-13 at 9.18.41 PM.png

API에서 데이터 가져오고 시작하기

SSR에서 API 데이터를 가져온채로 시작하려면 어떻게 해야할까요? 정답은 getInitialProps 메소드에 있습니다.

먼저
yarn add isomorphic-unfetch
를 터미널에 입력해줍시다. 우리는 이 모듈을 이용하여 fetch를 수행할 것입니다.

index.js의 소스를 다음과 같이 수정해봅시다

import Layout from "../components/Layout";
import Link from "next/link";
import fetch from "isomorphic-unfetch";

const ProfileLink = props => (
  <div>
    <Link href={`/p/[profile]`} as={`/p/${props.profile}`}>
      <a>Go to {props.profile}'s profile</a>
    </Link>
  </div>
);

const Index = props => (
  <Layout>
    <h1>Friends List {props.profiles[0]}</h1>
    {props.profiles.map((profile, index) => (
      <ProfileLink key={index} profile={profile} />
    ))}
  </Layout>
);

Index.getInitialProps = async function() {
  const res = await fetch("https://uinames.com/api/?amount=10");
  const data = await res.json();

  return {
    profiles: data.map(profile => profile.name)
  };
};

export default Index;

이제 결과를 확인하면 다음과 같습니다.

Screen Shot 2019-08-13 at 9.58.37 PM.png

API에서 생성된 무작위 이름이 생성됩니다.

Now를 이용하여 Next.js App 배포하기

npm install --global now

명령어를 이용하여 now를 깔아줍시다.

그리고 다음 명령어를 치면 끝납니다

now

처음 명령어를 입력하면 이메일 인증을 거치고 그 다음에 다시 명령어를 치면 다음과 같이 배포됩니다.

Screen Shot 2019-08-13 at 10.02.17 PM.png

이 과정을 거치고 파란색 URL주소로 접속해보면

우리의 사이트가 멋지게 배포되어 있습니다.

Screen Shot 2019-08-13 at 10.03.03 PM.png

수고하셨습니다.