[Next.js] 동적 렌더링, React -> Next.js로의 마이그레이션

jhkim·2023년 10월 16일
0

SPA

  • 서버로부터 새로운 페이지를 불러오지 않고 현재 페이지를 동적으로 다시 작성함
  • 현재 html을 가지고 변경되는 부분에 대해서만 서버에서 불러와 클라이언트 사이드에서 렌더링
  • 그렇다고 하나의 화면만 보여주는 것이 아니고, 다른 주소마다 다른 화면을 보여줌 (라우팅)
  • 앱의 규모가 커지면 js파일이 너무 커진다는 단점
  • 크롤러가 페이지 정보를 수집하지 못하여 페이지 검색이 어려움 - 검색 엔진 최적화 X

CSR의 특징

  • 유저가 브라우저를 통해 앱에 접속하면 브라우저에게 js정보가 들어 있는 빈 html 문서를 전달한다. 브라우저는 이 js파일을 다운로드하여 실행할 때까지 빈 화면을 보여 주고, js파일의 로드가 끝나면 리액트 코드가 UI를 동적으로 렌더링한다.
  • 브라우저가 js실행을 할 수 없거나, 요청 중인 상태라면 UI를 구성할 수 없다.
  • 초기 로드만 완료되면 이후 렌더링이 빠르고, 서버에는 data가 필요할 때에만 요청하므로 부담이 덜하다.
  • 초기 로드가 오래 걸리고 외부 라이브러리가 필요한 경우가 많다.

리액트의 경우 동작 흐름은 다음과 같다.

주소 접속시 js파일 다운로드 → reactDOM.render()를 통해 html렌더링 → 스크립트를 방금 만들어진 html에 연결 → 브라우저 완성

SSR의 특징

  • 서버 쪽에서 js를 실행하고 브라우저로 완성된 페이지만 전송한다. 다운로드 받는 즉시 화면이 보여지므로 클라이언트 입장에서 컨텐츠 로드 시간이 단축된다.
  • 모든 JS가 다운로드 및 실행되어 표시될 때까지 기다릴 필요 없음 → 완전히 렌더링된 페이지를 표시하는 데에 걸리는 시간 단축
  • 서버 쪽에서 JS를 실행하고, 브라우저로 완성된 페이지만 전송하는 SSR은 다운로드 받는 즉시 화면을 보여줌
  • 검색 엔진 크롤러가 콘텐츠를 쉽게 수집하고 색인화할 수 있는 장점 → 검색 엔진에 적합
  • 스트리밍: 서버 구성 요소를 사용하면 렌더링 작업을 청크로 분할하고 준비가 되면 클라이언트로 스트리밍할 수 있음 → 전체 페이지가 서버에서 렌더링될 때까지 기다리지 않고도 페이지의 일부를 더 일찍 볼 수 있음

App Router

Next.js에는 앱 라우터와 페이지 라우터가 있다. 페이지 라우터는 Next.js에서 13버전 이전부터 기본적으로 지원하는 클라이언트 중심 라우터이다. 서버에서 렌더링된 React 애플리케이션을 구축할 수 있게 한다.

React에 비해 라우팅 설정을 하지 않아도 /page폴더 파일 구조를 이용해서 기본적으로 제공하는 라우팅으로 효율적으로 개발할 수 있다.

앱 라우터는 13.4버전부터 안정화된 라우터로, Next.js 13버전부터 등장한 라우터이다. 앱 라우터는 https://example.com/mypage 라우팅을 위해 /app/mypage/index.js 파일을 생성해야 한다.

라우트 종류

  1. index routes
  • pages/index.js → /
  • pages/mypage/index.js → /mypage
  1. nested routes

Nested Router?

⇒ 유저 사용성을 위해 다른 페이지로 이동하고 돌아온 후에도 원래 페이지를 띄우고 있으며, 해당 페이지의 특정 탭으로 곧바로 접근할 수 있도록 하고 싶을 때

  • pages/mypage/settings.js → pages/mypage/settings
  • pages/mypage/profile.js → pages/mypage/profile
  1. dynamic routes

[id].tsx와 같이 대괄호로 감싸진 것은 다이나믹 라우팅으로, 미리 정의된 주소로만 라우팅하지 않고 사용자가 접근한 경로 혹은 상황에 따라 동적으로 라우팅을 제공한다

서버 렌더링 전략

정적 렌더링

  • 렌더링 결과가 캐시되어 CDN으로 푸시될 수 있음
  • 사용자에게 개인화되지 않은 데이터가 있고 정적 블로그 게시물이나 제품 페이지처럼 빌드시 알 수 있는 데이터가 있을 때 유용

동적 렌더링

  • 개인에게 맞춤화된 데이터가 있거나, 쿠키나 URL의 검색매개변수와 같이 요청시에만 알 수 있는 정보가 있을 때 사용

** 대부분의 웹사이트에서 경로는 완전히 정적이거나, 완전히 동적이지 않음

ex) 주기적으로 재검증되는 캐시된 제품 데이터를 사용하지만, 캐시되지 않은 개인화된 고객 데이터도 포함하는 페이지가 있을 수 있음

동적 렌더링으로 전환

  • 렌더링하는 동안 동적 기능이나 캐시되지 않은 데이터 요청이 발견되면 Next.js는 전체 경로를 동적으로 렌더링하도록 전환함
  • 렌더링 전략 선택은 자동으로 발생하므로 개발자가 선택할 필요가 없음 - 대신 데이터 캐시 및 재검증 시기를 선택하거나, 스트리밍 여부를 선택할 수 있음
  • cookies(), headers(), useSearchParams(), searchParams()등 요청 시에만 알 수 있는 정보에 의존하는 기능을 사용하면 동적 렌더링으로 선택됨

스트리밍

  • 서버에서 UI를 점진적으로 렌더링하는 기능 제공 (Next.js라우터에 내장)
  • 렌더링 전체가 완료되기 전에 페이지의 일부를 볼 수 있음



Nextjs로의 마이그레이션시 발생한 문제점

Recoil을 사용할 때의 문제점이 발생했다.
Next.js는 개발 중 파일이 변경되면 해당 파일을 다시 build하는데(핫리로드), 이 때 atom으로 만든 state가 재선언된다.

Expectation Violation: Duplicate atom key "~~".
This is a FATAL ERROR in production.
But it is safe to ignore this warning if it occurred because of hot module replacement.

항상 고유해야 하는 key값이 이 재선언 과정에서 재사용되므로, Recoil의 Atom key가 중복되는 문제가 발생한다.
이를 해결하기 위해 RecoilEnv를 통한 환경변수 재설정 혹은 atom key에 난수를 사용하는 방법이 있으나, 우리는 Zustand로 변경하여 해결했다.

0개의 댓글