[Next] Next js를 사용하여 SSR, CSR 구현

손종일·2020년 12월 5일
5

Next.js

목록 보기
1/5
post-thumbnail

Next.js

Next.js를 사용하면 React에서도 CSR, SSR을 혼합하여 빠른 성능을 구현할 수 있다.

Brower에서 실제로 보이는 화면을 어디서 최종적으로 만들어서 보여주는지, 어떻게 만드는지에 따라서 CSR과 SSR이 나뉘어지게 됩니다.

CSR (Client Sid Rendering)

처음에 웹 서버에 요청할 때 데이터가 없는 빈 HTML을 받아옵니다.

  • HTML과 CSS 파일들을 요청하고 로드되면 화면에 그려지게 됩니다.
  • Javascript를 동적 렌더링을 하게 됩니다.

장점

  • 처음 로딩했을 때, HTML과 Static 파일들만 다 받으면, 동적으로 빠르게 렌더링하기 때문에 사용자 UX가 좋다. (페이지 이동시 깜박거림, 새로고침이 없다)
  • 서버 요청이 줄게되어 서버 부담이 덜해진다.
    단점
  • SSR보다 초기 로딩 속도가 느리다.
  • 아주 중요한 SEO 문제가 발생한다.
    (검색엔진이 크롤링을 할 때, 서버에서 처음 받아온 파일이 빈 파일을 읽게되어 해당 사이트가 무슨 사이트인지, 어떠한 기능을 하는지 검색 엔진 노출이 정말 큰 단점이다. 쇼핑몰 등 검색어 노출이 필수인 경우에는 정말 큰 단점이된다.)

SSR (Server Sid Rendering)

처음에 웹 서버에 요청할 때 완전하게 만들어진 HTML을 받아온다.

  • 다 만들어진 HTML을 받아서 렌더링하게 된다.

장점

  • 초기 로딩 속도가 빠르다.
  • SEO가 가능.
    단점
  • 매번 요청해서 받기 때문에 페이지 이동시 깜박거림, 즉 새로고침이 된다.
  • 서버 요청 횟수가 증가하여 서버 부하가 커지게 된다.

React에서의 Next.js를 사용하여 SSR, CSR을 구현해보자!

  • pages 안의 파일들은 소문자이어야 한다.
  • pages 디렉토리 안의 index파일이 '/' 주소의 의미를 담고 있다.
--------------------------------------------------------------- pages/index.js
// next의 next/link를 사용하면 페이지 이동이 가능하고 CSR로 렌더링된다.
import Link from 'next/link';

function index() {

  return (
    <Layout>
      <h1>안녕</h1>
    </Layout>
  );
}

export default index;
--------------------------------------------------------------- pages/about.js
// import Link from 'next/link';

function About() {
  return (
    <div>
      <h1>안녕하세요 손종일이에요</h1>
    </div>
  );
}

export default About;

2. next js에서의 라우팅 적용

--------------------------------------------------------------- components/Header.js
import Link from 'next/link';

const linkStyled = {
  marginRight: '1rem',
};

function Header() {
  return (
    <div>
      <Link href="/">
        <a>Home</a>
      </Link>
      <Link href="/about">
        <a>소개</a>
      </Link>
    </div>
  );
}

export default Header;

3. 모든 페이지에서 공통된 Header를 사용하도록 적용해보기

--------------------------------------------------------------- components/Layout.js
import { Children } from 'react';
import Header from './Header';

function Layout({ children }) {
  return (
    <div>
      <Header />
      {children}
    </div>
  );
}

export default Layout;
--------------------------------------------------------------- pages/index.js
// next의 next/link를 사용하면 페이지 이동이 가능하고 CSR로 렌더링된다.
import Link from 'next/link';
import Layout from '../components/Layout';
import Head from 'next/head';

function index() {
  const linkStyle = {
    marginRight: '1rem',
  };

  return (
    <Layout>
      {/* next/head를 사용해서 현재 탭의 이름을 변경할 수 있다. */}
      <Head>
        <title>Index 페이지</title>
      </Head>
      <h1>안녕</h1>
      <h2>
        {/* 해당 소개글을 누루면 about로 이동하며 CSR로 작동한다 */}
        <Link href="/about">
          <a style={linkStyle}>소개글</a>
        </Link>
      </h2>
    </Layout>
  );
}

export default index;

4. getInitialProps 메소드 사용하여 CSS, SSR 혼합하여 사용해보기

getInitialProps 라는 메소드를 설정하여 해결할 수 있습니다.
Url로 접속하면 SSR / 클릭하여 link를 타고 들어가면 CSR

--------------------------------------------------------------- pages/ssr-csr-test.js
import React from 'react';
import Layout from '../components/Layout';

// 이 메소드가 서버 사이드에서도 실행될 수 있고, 클라이언트 사이드에서도 실행될 수 있습니다.
// 심지어 필요에 따라 prefetch도 될 수 있습니다.

class SSRTest extends React.Component {
  static async getInitialProps({ req }) {
    return req ? { from: 'server' } : { from: 'client' };
  }

  render() {
    return <Layout>{this.props.from}에서 실행이 되었습니다.</Layout>;
  }
}

export default SSRTest;
--------------------------------------------------------------- components/Header.js
import Link from 'next/link';

const linkStyled = {
  marginRight: '1rem',
};

function Header() {
  return (
    <div>
      <Link href="/">
        <a>Home</a>
      </Link>
      <Link href="/about">
        <a>소개</a>
      </Link>
      <Link href="/ssr-csr-test">
        <a>SSR 테스트</a>
      </Link>
    </div>
  );
}

export default Header;

5. 공통된 title 등 여러 페이지에서 중복으로 사용되는 경우에는 _document.js 파일에 지정하여 다른 파일에서 참조하도록 할 수 있습니다.

--------------------------------------------------------------- pages/_documetn.js
import Document, { Head, Main, NextScript } from 'next/document';
import { render } from 'react-dom';
import flush from 'styled-jsx/server';

export default class MyDocument extends Document {
  static getInitialProps({ renderPage }) {
    const { html, head } = renderPage();
    const styles = flush();

    return { html, head, styles };
  }

  // 만약 여러페이지에서 공통적으로 사용하는 헤더를 설정할 경우에는
  // 이렇게 작성하게 됩니다.
  render() {
    return (
      <html>
        <Head>
          <style>{`body { margin: 0 } /* custom! */`}</style>
          <title>Next js 연습</title>
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </html>
    );
  }
}

// 이렇게 될 경우엔 이 값을 기본적으로 설정하고, Head 컴포넌트가 사용된 페이지의 경우엔
// 이 기본값 위에 덮어 씌웁니다. (상단에 flush가 있는 이유는 스타일링 섹션에서 다시 다루겠습니다.)

6. 외부에서 받아온 데이터를 출력할 수 있습니다. (axios 요청)

--------------------------------------------------------------- ssr-test.js
import axios from 'axios';
import React from 'react';
import Layout from '../components/Layout';

class SSRTest extends React.Component {
  static async getInitialProps({ req }) {
    const response = await axios.get(
      'https://jsonplaceholder.typicode.com/users'
    );
    return {
      users: response.data,
    };
  }

  render() {
    const { users } = this.props;

    const userList = users.map((user) => (
      <li key={user.id}>{user.username}</li>
    ));
    return (
      <Layout>
        <ul>{userList}</ul>
      </Layout>
    );
  }
}

export default SSRTest;

7. webpack 설정하기 (Veloper님 강의 참조)

  • webpack의 경우에는 최상위 디렉토리에 다음과 같이 next.config.js를 만들어
    다음과 같이 설정하시면 됩니다.
  • 메뉴얼에 다르면 불러올 수 있는 파일 형식을 추가하기 위해서 loader를 추가하는건 좋지 않다.
    그 이유는 클라이언트 쪽 코드만 웹팩으로 번들되기 때문에 서버사이드렌더링에서 잘 작동하지 않습니다.
    그 대신 바벨 플러그인을 사용하라고 합니다.
    바벨 설정도 다음과 같이 설정하면 됩니다.
--------------------------------------------------------------- next.config.js
module.exports = {
  webpack: (config, { dev }) => {
    // Perform customizations to config

    //Importan: return the modified config
    return config;
  },
};
--------------------------------------------------------------- .babelrc
{
  "presets": [
    "next/babel",
    "stage-0"
  ]
}
profile
Allday

0개의 댓글