next.js
Next.js

 

이전 리액트로 SPA(Single-Page-Application) 형태의 간단한 텍스트 게시판을 만들어 봤었다. CSR(Client Side Rendering)은 서버로부터 첫 로드 시 모든 자원을 다운로드하여 브라우저에서 랜더링을 진행하는 방식이기 때문에 초기 로드 시간을 제외하고는 사용자는 부드럽게 이용할 수 있다.

 

 

직접 만들어본 간단한 게시판이다. 처음 접속 했을 때, 잠깐의 로딩 애니메이션이 보이고 첫 페이지가 랜더링 된다. 로딩 중에는 자바스크립트 파일과 게시판 데이터가 브라우저에 다운로드된다. 로딩이 완료됐다면 이때부터 서버와의 연결은 필요 없다. 페이지에서 게시판 글을 모두 읽을 수 있을뿐더러 인터넷 접속이 끊기더라도 글 읽기도 가능했다. 

 

 

 

Simple Forum

This website is a simple forum created by Nextjs.

www.simple-forum.site

 

Nextjs 프로젝트로 변경 됨

 

 

이렇게 CSR 방식은 모든 리소스가 브라우저에 있기 때문에 사용자 반응에 즉각 대응할 수 있다. (화면 깜빡임 없이 바로 원하는 데이터가 나타남) 하지만 서비스를 제공하는 입장이라면 SEO라는 단점이 존재.

 

이를 해결하기 위한 방법으로 SSR(Server-Side-Rendering)과 SSG(Static-Site-Generation) 방식을 사용한다. 이 방식은 Next.js 라이브러리에서 제공하므로 CRA와 같은 형태로 프로젝트를 만들어 사용하면 된다. (Gatsby라는 라이브러리도 존재하며 Vue.js의 경우 같은 Next.js 개발사인 Vercel의 Nuxt.js가 있다) 

 

SSR은 사용자의 요청을 받아 서버에서 미리 렌더링 된 HTML결과를 클라이언트(브라우저)에 넘겨주는 방식이다. 이전 CSR은 브라우저가 자바스크립트 파일을 다운로드하고 직접 렌더링을 했다면 이제는 브라우저가 렌더링이 완료된 HTML만 받아서 보여주기만 하면 된다.

 

ISR(Incremental Static Regeneration) 방식은 SSG 방식에 revalidate라는 추가 옵션을 부여해 일정 시간마다 getStaticProps()를 실행하는 방식이다. SSR과 SSG 방식의 중간 점으로 생각하면 쉽다.

 

 

SSR 동작 과정


  1. 사용자 요청
  2. 프론트 서버에서 HTML 렌더링
  3. 렌더링 된 HTML 사용자에게 반환 
  4. 사용자 브라우저는 전달받은 HTML 렌더링

SSG 동작 과정


  1. 프론트 서버에서 사용자에게 필요한 페이지들을 미리 준비
  2. 사용자 요청
  3. 이미 완성된 HTML을 반환
  4. 사용자 브라우저는 전달받은 HTML 렌더링

ISR 동작 과정


  1. 프론트 서버에서 사용자에게 필요한 페이지들을 미리 준비
  2. 사용자 요청
  3. 이미 완성된 HTML을 반환
  4. 설정한 시간 이후 페이지 재생성

 

각각의 렌더링 방식에는 장점과 단점이 존재한다. SSR의 경우 페이지 전환 시 로딩이 걸리는 경우 기존 html 파일을 로드하듯 깜빡임 현상과 모든 요청을 처리하므로 서버의 부하가 걸리기 쉬운 구조이고, SSG은 웹 문서가 많아질 경우 모든 페이지를 정적 파일로 만들기에는 어려움이 있다.

 

이 문제를 해결하기 위해 각 페이지마다 상황에 맞게 사용하면 된다.

 

Next.js의 장점

1. Dynamic Routing


Next의 장점으로 pages 폴더에 파일을 구성하면 알아서 라우팅 처리를 해준다. 기존 리액트 라우터 돔을 사용해 일일이 해주었던 라우팅 처리가 필요 없어졌다.

2. Automatic Code Splitting


코드에 리소스 임포트 여부를 파악해 필요한 JS파일만 로드해준다. 그래서 첫 페이지 로딩 속도가 제일 빠르고 나중에 필요한 리소스가 있는 경우 JS파일을 클라이언트로 전달한다.

 

- 자주 사용하는 리소스의 경우 main JS bundle로 이동한다고 함.

3. ServerSide Rendering


빠른 렌더링과 SEO 최적화 가능

Next.js 기본 구조


- pages: HTML Document, Application Container, 각종 페이지 등을 작성한다.
  ㄴ _document.js: SPA에서 시작점이 되는 index.html <head>태그 내용 등을 작성
  ㄴ _app.js: Application Container. 공통의 레이아웃을 작성
  ㄴ _error.js: Error Page. ㄴ index.js // Root Page /로 시작되는 경로
  ㄴ hello.js: Hello Page /hello로 시작되는 경로
- public: 정적 파일 (이미지, 파일 등)을 보관.
- next.config.js: Next.js의 환경 설정 파일

_document.js


  • React LIFECYCLE과 DATA FETCHING이 불가능
  • <head> 태그 안에 작성될 CDN이나 공통으로 추가될 meta태그를 작성

_app.js


  • 공통되는 레이아웃을 작성
  • 에러 핸들링이나 라우팅 되었을 때의 프로그래싱 처리 가능

_error.js


  • 에러 페이지에서 공통으로 사용된다.
  • 작성하지 않을 경우 Nextjs에서 디폴트 값을 알아서 사용

next.config.js


  • 웹팩 플러그인과 Nextjs 라우팅 설정을 작성

Next.js 시작하기


> npx create-next-app my-app

 

nextjs
Next.js 폴더구조

 

 

Create-Next-app을 사용하여 프로젝트를 만들면 위와 같은 폴더구조가 생성된다. 기존 CRA에서 있던 src폴더가 pages폴더로 바뀌었다. 위 components 폴더는 수동으로 생성했고 pages에는 index.js 파일이 존재한다. 만약 pages폴더에 intro.js라는 파일을 생성하면 localhost:3000/intro처럼 접속 가능하다. 즉, Nextjs는 다이나믹 라우팅을 지원한다.

getInitialProps()


getInitialPropss는 데이터 초기값을 미리 요청해 컴포넌트에 전달하여 서버 사이드 랜더링을 도와준다. 어찌 보면 getServerSideProps()와 같은 기능이지만 다른 점이 있다. 처음 로드될 때에는 서버에서 실행되지만 next/router나 next/Link를 통해서 로드될 경우 클라이언트에서 실행된다는 점이다. 

 

function Page({ stars }) {
  return <div>Next stars: {stars}</div>
}

Page.getInitialProps = async (ctx) => {
  const res = await fetch('https://api.github.com/repos/vercel/next.js')
  const json = await res.json()
  return { stars: json.stargazers_count }
}

export default Page

 

_app.js에서 getInitialProps를 사용하면 조금이나마 서버의 부담을 줄일 수 있다.

getServerSideProps()


export const getServerSideProps = async(context) => {

   return {
     props : { 
	     // will be passed to the page component as props
     }
   }
}

 

getInitialProps와 같이 SSR 방식을 사용하려면 getServerSideProps()를 사용한다. 이 함수는 페이지 요청시 매번 실행되기 때문에 최신 데이터를 보여주는 컴포넌트 사용에 적합함. 대게 외부 데이터를 async/await 비동기 처리를 통해 가져와 props로 넘겨주면 해당 컴포넌트에서 넘겨받아 적절한 위치에 데이터를 세팅해주면 된다.

 

context 하위 키

  • params: 이전에 나온 내용과 동일
  • req: The HTTP request object.
  • res: The HTTP response object.
  • query: The query string.

getStaticProps()


export const getStaticProps = async() => {
  
    const res = await fetch(`https://jsonplaceholder.typicode.com/posts?_start=0&_end=5`);
    const posts = await res.json();
  
    return {
      props : {
        posts
      },
      revalidate : 20
    }
}

 

SSG 방식을 사용할 때에는 getStaticProps() 를 사용한다. getStateProps()는 빌드 타임에 생성되는 HTML을 요청이 올 때 재사용한다. SSR은 요청마다 새로운 HTML을 만들어 전송했다면, 이 번에는 미리 만들어 둔다는 말이다.

 

보통 정적으로 사용되는 경우 getStaticProps를 사용하면 되고 데이터 변경이 잦은 경우 getServerSideProps를 사용하면 된다. 하지만 ssr 방식은 서버에 무리가 많아 getStaticProps에서 revalidate 옵션으로 일정 주기로 ssr 방식을 흉내 낼 수 있다.

 

 

반환 객체

 

  • props - 페이지 구성 요소에 포함될 선택적 개체
  • revalidate - 페이지 재생성이 발생할 수 있도록 하는 초 단위의 값. 기본값은 false  
  • notFound - 페이지가 404 상태 및 페이지를 반환할 수 있도록 하는 선택적 불리언 값.

getStaticPaths()


Nextjs에서는 동적 라우팅(pages/post/[id]/index.js) 처리를 할 때  id로 들어갈 각각의 페이지들을 getStaticPaths로 지정해 주어야한다. 

 

여기에 라우팅 되는 모든 경로를 계산해 넣어야 미리 페이지를 만들어 놔서 바로 접근가능하다. 

 

// This function gets called at build time
export async function getStaticPaths() {
  return {
    //빌드 타임 때 아래 정의한  /post/1,  /post/2, ... /post/동적인값 경로만 pre-render.
    const paths = posts.map((post) => {
    	params = { id : post.id }, // post/:id <- post.id
    }),
    // 만들어지지 않은 것도 추후 요청이 들어오면 만들어 줄 지 여부.
    fallback: true,
  }
}

 

Nextjs 프로젝트를 빌드하면 .next/server/pages/post 경로에 보면 모든 동적 경로의 페이지들이 만들어진다. 

 

출처 및 참고시 도움 되는 글


 

 

Basic Features: Data Fetching | Next.js

Next.js has 2 pre-rendering modes: Static Generation and Server-side rendering. Learn how they work here.

nextjs.org

 

Next.js 공식 Docs 흝기

일하기 전 쓰윽 흝기.

velog.io

 

Dev.log

salgum1114 Dev.log

salgum1114.github.io