기본적으로 SPA를 구성하는 방식이 CSR이다.
하나의 html파일로 여러 페이지를 구현하는 방식의 애플리케이션
HTML 태그를 자바스크립트가 동적으로 생성한다.
조금 더 자세히 얘기하면,
웹 페이지의 렌더링이 클라이언트 측에서 일어나는 것
데이터를 유동적으로 호출해야 하지만 SEO가 필요없는 마이페이지, 관리 페이지 등은 CSR방식으로 만들면 된다.
CRA로 빌드한 프로젝트는 CSR로만 실행되기 때문에, 검색 노출이 잘 되지 않는다.
반대로 어드민 페이지나 특정 조건(유료 멤버십 페이지, vip 페이지 등)은 특별히 검색노출이 필요하지 않기 때문에 CRA로 충분히 개발할 수 있다.
서버에서 첫 페이지의 렌더링을 처리해주는 방식
페이지 요청이 발생했을 때 서버에서 api를 호출해 데이터를 가져와 html을 완성시키고 클라이언트에 전달한다.
CSR에 비해 페이지를 구성하는 속도는 늦어지지만, 전체적으로 사용자에게 보여주는 콘텐츠 구성이 완료되는 시점은 빨라진다. => 이게 무슨 말이냐면...
SSR은 아래 이미지와 같이 동작한다.
서버에서 html파일을 준비해 보내주면 바로 화면을 그려 사용자에게 보여줄 수 있다.
이후 JS파일을 로드하고, 실행시켜 페이지의 구성을 완료한다.
따라서 사용자의 입장에서 화면을 빠르게 볼 수 있다.
이미지 출처: The Benefits of Server Side Rendering Over Client Side Rendering
반면 CSR은 빈 html파일을 받아온 후, JS파일을 다운받고, 이 JS코드를 실행해 DOM을 화면에 모두 그린 후에야 사용자에게 보여줄 수 있기 때문에, 사용자에게 화면을 보여주기 위한 시간은 상대적으로 더 많이 소요된다.
Next.js는 SSR과 CSR을 섞어 쓸 수 있도록 하는 리액트 프레임 워크이다.
CRA는 별도의 초기 설정 없이도 리액트 기반의 SPA 사이트를 구현하도록 도와준다.
하지만 CSR방식으로 빌드하는데, 이렇게 되면 SEO가 잘 되지 않는다.
코드 스플리팅이란?
코드 스플리팅은 한 개의 파일에서 처음부터 모든 걸 불러오지 않고, 당장 필요하지 않은 코드는 분리시킨 다음 필요할 때 불러 사용하는 것이다.
SPA의 경우 자바스크립트 번들 파일에 어플리케이션에 대한 모든 로직을 불러오기 때문에 프로젝트 규모가 커질 경우 용량 또한 커진다고 위에서 언급했다.
코드 스플리팅을 사용하면 페이지의 로딩 속도를 개선할 수 있다.
다시 말하면, 데이터까지 포함된 완성된 html파일을 미리 만들어둔 뒤 페이지 요청이 잇을 때 이 페이지를 바로 응답한다.
이 렌더링 방식은 어떻게 구현하면 될까?
Next.js에서 제공하는 데이터 호출 메서드들이 있다.
이 메서드로 데이터를 호출해 사용하면, 그대로 렌더링 방식이 결정된다.
import { GetStaticProps } from 'next'
export const getStaticProps: GetStaticProps = async context => {
// 생략
}
동적라우트인 페이지면서 정적으로 페이지를 생성하고 싶을 때 사용하는 메서드
동적라우트로 생성될 모든 경로에 대해 getStaticProps와 마찬가지로 빌드 시점에 데이터를 받아 페이지를 정적으로 생성한다.
export const getStaticPaths: GetStaticPaths = async () => {
return {
paths: [{ params: { id: '1' } }, { params: { id: '2' } }]
};
};
export const getStaticProps: GetStaticProps = async ({ params }) => {
const response = await axios(`${API_URL}/restaurant?id=${params.id}`);
return {
props: {
data: response.data.restaurant
}
};
};
getInitialProps라는 메서드도 있지만, Next.js 9.3버전 이후로 getSererSideProps가 더 기능이 좋아졌기 때문에 사용하지 않아도된다.
export const getServerSideProps: GetServerSideProps = async () => {
const all = await axios(`${API_URL}/restaurants`);
return {
props: {
data: all.data.restaurants
}
};
};
fetch 함수는 web API이기 때문에 브라우저에서만 실행된다.
즉 서버측에서 호출할 수 없다.
클라이언트와 서버측 모두 api를 호출할 수 있도록 axios를 쓰는 것이 좋다.