Next.js를 사용하면 React에서도 CSR, SSR을 혼합하여 빠른 성능을 구현할 수 있다.
처음에 웹 서버에 요청할 때 데이터가 없는 빈 HTML을 받아옵니다.
- HTML과 CSS 파일들을 요청하고 로드되면 화면에 그려지게 됩니다.
- Javascript를 동적 렌더링을 하게 됩니다.
장점
- 처음 로딩했을 때, HTML과 Static 파일들만 다 받으면, 동적으로 빠르게 렌더링하기 때문에 사용자 UX가 좋다. (페이지 이동시 깜박거림, 새로고침이 없다)
- 서버 요청이 줄게되어 서버 부담이 덜해진다.
단점- SSR보다 초기 로딩 속도가 느리다.
- 아주 중요한 SEO 문제가 발생한다.
(검색엔진이 크롤링을 할 때, 서버에서 처음 받아온 파일이 빈 파일을 읽게되어 해당 사이트가 무슨 사이트인지, 어떠한 기능을 하는지 검색 엔진 노출이 정말 큰 단점이다. 쇼핑몰 등 검색어 노출이 필수인 경우에는 정말 큰 단점이된다.)
처음에 웹 서버에 요청할 때 완전하게 만들어진 HTML을 받아온다.
- 다 만들어진 HTML을 받아서 렌더링하게 된다.
장점
- 초기 로딩 속도가 빠르다.
- SEO가 가능.
단점- 매번 요청해서 받기 때문에 페이지 이동시 깜박거림, 즉 새로고침이 된다.
- 서버 요청 횟수가 증가하여 서버 부하가 커지게 된다.
1. import Link from 'next/link'를 사용하면 다른 페이지로 라우팅되며 CSR로 동작하도록 할 수 있다.
--------------------------------------------------------------- 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" ] }