Jaeseo's Information Security Story

[Next.js] - 튜토리얼(2) Dynamic Route CSR, SSR 요청 구분 하기! 본문

Coding and Linux Study/React

[Next.js] - 튜토리얼(2) Dynamic Route CSR, SSR 요청 구분 하기!

Jaeseokim 2020. 5. 3. 21:24

Next를 사용하는 가장 큰 이유중 하나인 "Pre-Rendering" 기능에 대해 공부를 하면서 깨달은 점 몇가지가 있어서 정리를 해보았습니다.

getInitialProps 를 이용한 CSR, SSR 요청 구분

Next.js의 문서를 보게 되면 getInitialProps 함수가 실행 될 때 넘어오는 context 의 값에 대해서 설명하는 부분이 있습니다.

getInitialProps receives a single argument called context, it's an object with the following properties:

  • pathname - Current route. That is the path of the page in /pages
  • query - Query string section of URL parsed as an object
  • asPath - String of the actual path (including the query) shown in the browser
  • req - HTTP request object (server only)
  • res - HTTP response object (server only)
  • err - Error object if any error is encountered during the rendering

여기서 보게 되면 req, res 부분은 server only 라고 적혀 있는데 이부분을 이용하여 CSR과 SSR 요청에 대해 구분하는 것을 바로 이 req와 res을 이용하여 구분을 할 수 있습니다.

실제로 동작하는지 테스트를 하기 위해 코드를 간단하게 작성 해 봤습니다.

index.js

import Link from "next/link";

export default function Home() {
  return (
    <div className="grid">
      <Link href="/csr-ssr">
        <a>
          <h3>CSR-SSR &rarr;</h3>
        </a>
      </Link>
    </div>
  );
}

csr-ssr.js

const CSRSSR = ({ isSSR }) => {
  return (
    <div>
      <h1>{isSSR}</h1>
    </div>
  );
};

CSRSSR.getInitialProps = async (context) => {
  const { req } = context;
  return { isSSR: req ? "server" : "client" };
};

export default CSRSSR;

위 처럼 클라이언트 단에서 <Link> 를 통해 이동한 것에 대해서는 client 측에서 요청했다고 뜨게 되고 이제 직접적으로 URL로 접근을 하게 되면 server 라고 뜨는 것을 확인 할 수 있습니다.

이제 이 점을 활용하여 API 서버에 데이터를 요청 하여 화면에 출력 하는 경우에는 이렇게 URL에 대해서 요청을 할 시에만 서버에서 API 요청을 보내고 받은 데이터를 가지고 Pre-redering를 하는 것이 가능 해 집니다.

한번 https://jsonplaceholder.typicode.com/posts/1 의 API를 사용하여 SSR를 만들어 봅니다.

여기서 useSWRisomorphic-unfetch 을 사용 했습니다.

csr-ssr.js

import fetch from "isomorphic-unfetch";
import useSWR from "swr";

const CSRSSR = ({ article, isClient }) => {
  if (isClient) {
    const { data } = useSWR(
      "https://jsonplaceholder.typicode.com/posts/1",
      async (...args) => {
        const res = await fetch(...args);
        return res.json();
      }
    );
    article = data;
  }

  if (!article) {
    return <h1>isLoding....</h1>;
  }

  return (
    <div>
      <h1>{article.title}</h1>
      <span>{article.body}</span>
    </div>
  );
};

CSRSSR.getInitialProps = async ({ req }) => {
  if (req) {
    const res = await (
      await fetch("https://jsonplaceholder.typicode.com/posts/1")
    ).json();
    return {
      article: res,
    };
  } else {
    return {
      isClient: true,
    };
  }
};

export default CSRSSR;

위 코드를 보게 되면 req가 존재 하게 되면 즉 서버에서 요청된 것 이라면 서버에서 데이터를 미리 fetch 해서 전달을 하게 됩니다. 그렇기 때문에 초기부터 html에 데이터를 가지고 오게 때문에 SEO 즉 검색에 대해서도 처리가 가능합니다.

이제 클라이언트에서 요청을 하게 되면 서버에서는 데이터를 fetch 해서 전달을 하지 않기 때문에 초기에 loding 화면이 보이게 되고 데이터에 대해 fetch가 끝나게 되면 이제 내용이 로딩이 되는 것을 볼 수 있습니다.

Dynamic Route의 getInitialProps 를 이용한 CSR, SSR 요청 구분

이제 동적인 라우팅에 대해서 처리 하는 것을 알아 봅니다. (

여기서 맨 처음 정확하게 몰라서 고생을 했네요 .. ㅠㅠ

)

/test/[id].js

const test = ({ isSSR, id }) => {
  return (
    <div>
      <h1>{isSSR}</h1>
      <h2>{id}</h2>
    </div>
  );
};

test.getInitialProps = async (ctx) => {
  const { req } = ctx;
  const {
    query: { id },
  } = ctx;
  return { isSSR: req ? "server" : "client", id };
};

export default test;

index.js

import Link from "next/link";

export default function Home() {
  return (
    <div className="grid">
      <Link href="/test/1">
        <a>
          <h3>test1 &rarr;</h3>
        </a>
      </Link>

      <Link href="/test/[id]" as={`/test/2`}>
        <a>
          <h3>test2 &rarr;</h3>
        </a>
      </Link>
    </div>
  );
}

여기서 보게 되면 중간에 차이가 있는 것을 알 수 있는데 Next.js에서 route간의 이동은 Link 컴포넌트를 이용하게 됩니다. 그리고 보통의 a 태그처럼 herf 를 쓰게 되는데 이때 경로는 /pages 밑의 경로의 js와 맵핑이 됩니다.

이때 Dynamic Route 에 대해서 test1과 같이 사용하게 되면 /pages/test/1.js 파일에 대해 용청을 하게 되기 때문에 존재가 하지 않아 평범하게 url에 대해 요청을 하여 SSR 처리가 됩니다.

test처럼 /pages/test/[id].js 파일에 대해 요청을 하고 그 다음 as property에서 어떤 URL로 변경해서 사용 할 것 인지에 대해 알려주어야 합니다.

 

이제 간단하게 https://jsonplaceholder.typicode.com/ API를 사용하여 URL에 대해서 접근하는 경우에만 SSR를 진행 하는 게시판을 만듭니다.

index.js

import fetch from "isomorphic-unfetch";
import useSWR from "swr";
import Link from "next/link";

export default function Home() {
  const { data: articleList } = useSWR(
    "https://jsonplaceholder.typicode.com/posts",
    async (...args) => {
      const res = await fetch(...args);
      return res.json();
    }
  );

  if (!articleList) {
    return <h1>Loding...</h1>;
  }

  return (
    <div className="grid">
      {console.log(articleList)}
      {articleList.map((value) => (
        <Link href="/posts/[id]" as={`/posts/${value.id}`}>
          <a>
            <h3>{value.title} &rarr;</h3>
          </a>
        </Link>
      ))}
    </div>
  );
}

/posts/[id].js

import fetch from "isomorphic-unfetch";
import useSWR from "swr";
import { useRouter } from "next/router";

const CSRSSR = ({ article }) => {
  const router = useRouter();
  const {
    query: { id },
  } = router;
  const { data } = useSWR(
    `https://jsonplaceholder.typicode.com/posts/${id}`,
    async (...args) => {
      const res = await fetch(...args);
      return res.json();
    },
    { initialData: article }
  );
  article = data;

  if (!article) {
    return <h1>isLoding....</h1>;
  }

  return (
    <div>
      <h1>{article.title}</h1>
      <span>{article.body}</span>
    </div>
  );
};

CSRSSR.getInitialProps = async ({ req, query: { id } }) => {
  if (req) {
    const res = await (
      await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`)
    ).json();
    return {
      article: res,
    };
  } else {
    return {};
  }
};

export default CSRSSR;

위와 같이 정상적으로 Client 요청은 클라이언트에서 Fetch 하여 Dom를 구성하고 URL에 대해서 접근 한 경우에는 서버에서 내용을 Fetch 하여 내용이 들어간 HTML를 전달 하는 모습을 볼 수 있습니다.

이 점을 활용 하게 되면 서버의 부담을 줄이고 또 SPA 어플의 SEO 최적화에 도움이 될 것 같습니다.

 

 

https://csr-ssr-check.jaeseokim.now.sh/

 

csr-ssr-check.jaeseokim.now.sh

 

 

JaeSeoKim/Next.js-getInitialProps-csr-ssr-check

[Next.js] getInitialProps를 이용한 SSR, CSR 구분 및 PreRendering - JaeSeoKim/Next.js-getInitialProps-csr-ssr-check

github.com

 

Comments