본문 바로가기

Development

React에 Next.js 도입하기

반응형

현재 React + Javascript로 구성된 애플리케이션에 Next.js를 도입해보려한다! 처음해보는거라 신난다 😁

1. next 설치

원래 react, react-dom, next 설치가 필요한데 이미 react, react-dom은 설치되어 있던 상황이라 추가로 next만 설치했다.

 

$ yarn add next

2. pages/ + pages/index.js 생성

Next.js는 pages라는 폴더를 꼭 필요로 한다! 그래서 최상위 디렉토리에 pages 폴더를 만들고, 첫 화면을 보여주는 index.js를 생성했다.

 

 

// pages/index.js

import React from 'react';

const Index = () => {
  return <div>첫 화면</div>;
};

export default Index;

3. next 실행을 위해 package.json의 script 수정 

// package.json

"scripts": {
  "build": "webpack --mode=production --node-env=production",
  "build:dev": "webpack --mode=development",
  "start": "webpack serve",
  "next": "next" // 추가 부분
 }

4. next 실행

$ yarn next

 

위 명령어로 next를 실행했더니

 

짜잔 이런게 뜬다 ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ 역시...한번에 안되는군 ㅡㅡ

해결법

@babel/runtime과 @babel/plugin-transform-runtime을 설치해 regenerator-runtime을 추가하는 방식으로 해결했다.

 

1. @babel/runtime 설치

 

$ yarn add @babel/runtime

 

2. @babel/plugin-transform-runtime 설치

 

$ yarn add -D @babel/plugin-transform-runtime

 

3. .babelrc plugins에 "@babel/plugin-transform-runtime" 추가

 

// .babelrc

{
  "plugins": ["@babel/syntax-dynamic-import", "@babel/plugin-transform-runtime"],
  "presets": [
    "@babel/preset-react",
    [
      "@babel/preset-env",
      {
        "modules": "auto"
      }
    ]
  ]
}

 

요로코롬 하고 다시 실행했더니 아주 휑---한 원하던 첫화면이 나왔당 ㅎㅎㅎ

 

 

나는 현재 src/components/SpinButton/SpinButton 컴포넌트를 제일 첫 화면으로 보여주고 싶은 상황이다. 이어서 해보겠다.

5. pages/_document.js 작성

_document.js는 전체 페이지에 관여하는 컴포넌트로 HTML, head, body를 담당한다고 볼 수 있다. 이 문서 작성에는 몇 가지 규칙이 있다.

 

1. _document를 작성할 때는 Document 클래스를 상속받는 클래스 컴포넌트로 작성해야만 하며, 렌더 함수는 꼭 <Html>, <Head>, <Main>, <NextScript> 요소를 리턴해줘야한다.

 

2. _document에서 사용하는 <Head> 태그는 next/head가 아닌 next/document 모듈에서 불러와야 한다. _document의 <Head> 태그에는 모든 문서에 공통적으로 적용될 내용(Ex. charset 등)이 들어가야 한다.

 

3. _document는 서버에서 실행되므로 브라우저 api 또는 이벤트 핸들러 등을 포함하지 않아야 한다.

 

4. <Main /> 부분을 제외한 부분은 브라우저에서 실행되지 않으므로 비즈니스 로직을 추가해서는 안된다.

 

나의 경우에는 CSR → SSR로 바꾸는 과정이었다. 따라서 이미 public/index.html에 작성된 내용을 참고로 옮겼다.

 

+추가)

이렇게 _document.js를 작성하니 나중에 next 실행 시 다음과 같은 warning이 났다.

Adding <title> in pages/_document.js will lead to unexpected results with next/head since _document.js is only rendered on the initial pre-render.

출처 https://nextjs.org/docs/messages/no-document-title

 

그래서 공식문서 를 참고해서 _app.js와 _document.js를 수정했다.

 

변경된 _document.js

 

import React from 'react';
import Document, { Html, Head, Main, NextScript } from 'next/document';

export default class CustomDocument extends Document {
  render() {
    return (
      <Html lang="ko">
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

 

변경된 _app.js

 

import React from 'react';
import Head from 'next/head';

const App = ({ Component, pageProps }) => (
  <>
    <Head>
      <meta charSet="utf-8" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      <meta name="description" content="엘라의 항공사 웹사이트의 컴포넌트 접근성 높이기 미션" />
      <title>Ella's airline</title>
    </Head>
    <Component {...pageProps} />
  </>
);

export default App;

 

6. pages/_app.js 작성

_app.js에서 렌더링하는 값은 모든 페이지에 영향을 준다. _app.js는 클라이언트에서 띄우길 바라는 전체 컴포넌트의 공통 레이아웃이다. 전체 페이지를 감싸고 있는 root 페이지라고 볼 수 있다.

 

****이 _app.js는 구버전입니다. 바로 위 변경된 _app.js와 _documnet.js를 확인해주세요****
// pages/_app.js

import React from 'react';

const App = ({ Component, pageProps }) => <Component {...pageProps} />;

export default App;

 

여기서 props로 받은 Component는 요청한 페이지이다. GET/ 요청을 보내면, Component에는 pages/index.js 파일이 props로 내려온다. pageProps는 페이지 getInitialProps를 통해 내려 받은 props들을 말한다.

 

_app.js 실행 후 _document.js가 실행된다.

7. pages/index.js 수정

난 일단 별다른 페이지 없이 SpinButton 컴포넌트만 첫 화면에 띄울 예정이다. 따라서 첫 화면을 담당하는 pages/index.js 를 수정한다.

 

import React from 'react';
import { SpinButton } from '../src/components';

const Index = () => {
  return <SpinButton />;
};

export default Index;

 

이렇게 하니 원하던 화면이 첫 화면으로 나왔다 ㅎㅎ

 

 

여기까지 오니 페이지 이동도 한 번 해보고 싶어졌따! 그래서 도전!!

 

next.js에서는 pages/ 안의 내용을 참고로 url이 설정된다. 예를들면 다음과 같다.

 

pages/index.js → '/'

pages/carousel.js → '/carousel'

8. pages/carousel.js 추가

import React from 'react';

const Carousel = () => (
  <div>
    🎯 미션2 Carousel: 지금 떠나기 좋은 여행이 담겨있었어야 할 페이지
  </div>
);

export default Carousel;

9. carousel.js로 갈 수 있는 a태그 및 Link 추가

// pages/index.js

import React from 'react';
import { SpinButton } from '../src/components';
import Link from 'next/link';

const Index = () => {
  return (
    <>
      <SpinButton />

      <Link href="/carousel">
        <a>Carousel 페이지로 가기</a>
      </Link>
    </>
  );
};

export default Index;

 

요로코롬하고 라우터가 잘 동작하는지 확인해봤다. 아주 잘 동작한다.

 

 

 

추가로 SSR이 잘 적용됐나 궁금해서 개발자 도구로 열어보니 이렇게 이미 완성된 index.html이 응답으로 온당! 신기하다!!! 

 

SSR이 적용된 응답

 

 

CSR일 때 응답

 

 

출처

https://merrily-code.tistory.com/154

https://kyounghwan01.github.io/blog/React/next/basic/#동적-url

https://23life.tistory.com/147

https://23life.tistory.com/148

반응형