jineecode

NEXT.JS Data Fetching 본문

JS/react

NEXT.JS Data Fetching

지니코딩 2021. 11. 24. 11:27

1. SSR

https://d2.naver.com/helloworld/7804182

SSR은 무엇인가?

SSR은 서버에서 사용자에게 보여줄 페이지를 모두 구성하여 사용자에게 페이지를 보여주는 방식이다. JSP/Servlet의 아키텍처에서 이 방식을 사용했다.

 

SSR을 사용하면 모든 데이터가 매핑된 서비스 페이지를 클라이언트(브라우저)에게 바로 보여줄 수 있다. 서버를 이용해서 페이지를 구성하기 때문에 클라이언트에서 구성하는 CSR(client-side rendering)보다 페이지를 구성하는 속도는 늦어지지만 전체적으로 사용자에게 보여주는 콘텐츠 구성이 완료되는 시점은 빨라진다는 장점이 있다. 더불어 SEO(search engine optimization) 또한 쉽게 구성할 수 있다.

 

반면 CSR은 SSR보다 초기 전송되는 페이지의 속도는 빠르지만 서비스에서 필요한 데이터를 클라이언트(브라우저)에서 추가로 요청하여 재구성해야 하기 때문에 전제적인 페이지 완료 시점은 SSR보다 느려진다.

 

출처: The Benefits of Server Side Rendering Over Client Side Rendering

 

The Benefits of Server Side Rendering Over Client Side Rendering

Most of our pages on walmart.com are using server side rendering (henceforth SSR) with only a few unique exceptions.

medium.com

 

외부 데이터를 필요로 하지 않는다면 넥스트는 빌드 시에 페이지를 렌더링하여 요청시마다 제공.

외부 데이터를 필요로 한다면 SSR을 통해 외부 데이터를 이용하여 렌더링을 한 후, HTML을 제공. 

 


https://nextjs.org/docs/basic-features/data-fetching

 

Basic Features: Data Fetching | Next.js

Next.js has 2 pre-rendering modes: Static Generation and Server-side rendering. Learn how they work here.

nextjs.org

 

 

getServerSideProps


페이지의 데이터를 서버로부터 제공받는 기본 API. 서버에서 데이터를 패치하여 초기 데이터를 전달하도록 구성되어있음.

export async function getServerSideProps(context) {
  const res = await fetch(`https://...`)
  const data = await res.json()

  if (!data) {
    return {
      notFound: true,
    }
  }

  return {
    props: {}, // will be passed to the page component as props
  }
}

...화살표함수...

export const getServerSideProps = async () => {
  try {
    const res = await fetch(`https://...`);
     if(res.status === 200) {
          const user = await res.json();
          return {props: {user}};
          // 응답에 성공할 경우 user 정보를 props로 전달
        }
        return {props: {}};
     } catch(e) {
        console.log(e);
        return {props: {}};
        // 응답에 실패할 경우 아무것도 전달하지 않는다.
 }
 
 // 데이터 요청은 에러가 발생할 수 있기 때문에 항상 try, catch를 이용하는 게 좋다.

  return {
    props: {}, // will be passed to the page component as props
  }
};

서버 측에서 props를 받아오는 기능을 함.

페이지를 요청 시마다 실행이 되며 getServerSideProps에서 페이지로 전달해준 데이터를 서버에서 렌더링하게 됨.

그러므로 브라우저가 아닌 터미널에서 콘솔 출력이 된다.

 

NotFound에 true값을 주면 404응답을 받게된다.
getServerSideProps에서 사용하기 위한 모듈은 최상단에 import하여 사용 가능하다.
getServerSideProps에 사용된 모듈들은 클라이언트 측에 번들로 제공 되지 않는다.
즉, 이 영역에서는 서버 측 코드를 작성 할 수 있게 된다.
예를 들어 숨기고 싶은 api url 또는 파일 읽기, 데이터베이스 읽기 등이 포함된다.

getServerSideProps는 항상 페이지 내에 사용되는 데이터가 최신이어야 할 때 사용해야 한다.
매번 페이지가 요청 될때 마다 getServerSideProps를 통해 프리랜더링 과정이 일어나
Time to first Byte (TTFB) 가 getStaticProps보다 느리기 때문이다.
또, getServerSideProps는 추가 설정 없이는 결과가 CDN에 캐시되지 않는다는 점도 있다.

데이터를 미리 페이지에 그려야 하는 상황이 아니라면 클라이언트 사이드에서 데이터를 받아 오는 방식을 고려하는 것이 좋다.

 

 

getStaticProps


빌드 시에 데이터를 불러와 결과를 json으로 저장하여 사용함. 따라서 일관된 데이터를 보여준다.

export async function getStaticProps(context) {
  const res = await fetch(`https://.../data`)
  const data = await res.json()

  if (!data) {
    return {
      notFound: true,
    }
  }

  return {
    props: { data }, // will be passed to the page component as props
  }
}


...화살표 함수...

import fetch from 'isomorphic-unfetch';

const name = ({ user, time }) => {
  const username = user && user.name;
  return (
    <div>
      {username}
      {time}
    </div>
  );
};
export const getStaticProps = async ({ params }) => {
  try {
    const res = await fetch(`https://api.github.com/users/${params.name}`);
    if (res.status === 200) {
      const user = await res.json();
      return { props: { user, time: new Date().toISOString() } };
    }
    return { props: { time: new Date().toISOString() } };
  } catch (e) {
    console.error(e);
    return { props: { time: new Date().toISOString() } };
  }
};

export async function getStaticPaths() {
  return {
    paths: [{ params: { name: 'jerrynim' } }],
    fallback: false,
  };
}

export default name;

빌드 시 시간이 변하지 않는다. revalidate 옵션을 쓰면 정적 데이터가 갱신된다.

  • revalidate - An optional amount in seconds after which a page re-generation can occur. Defaults to false. When revalidate is false it means that there is no revalidation, so the page will be cached as built until your next build. More on Incremental Static Regeneration
 

Basic Features: Data Fetching | Next.js

Next.js has 2 pre-rendering modes: Static Generation and Server-side rendering. Learn how they work here.

nextjs.org

query 대신 params 를 사용.

getStaticPaths를 이용해서 params를 미리 지정해야만 함.

fallback: 지정한 경로 외의 경로에 대해 설정함. false는 404 에러로 가게 된다.

getStaticPaths는 페이지의 경로가 외부 데이터에 의존할 때 사용하게 된다.

 

  • 유저의 요청(request)이 있기 전에 렌더링 대상이 되는 페이지를 사전에 렌더링해야되는 경우 사용한다.
  • 보통 build time에 사전 렌더링을 해둔다.

 1-1 데이터가 없는 경우

데이터가 없는 경우는, 서버로부터 fetch해 올 어떠한 데이터도 없기 때문에 Next.js에서는 build time에 HTML 형태로 사전 렌더링을 해둔다.

 

이게 무슨 소리냐면, 일반적인 react 의 경우 개발자 도구를 열어보면 

<div id="root"></div>

만 보이는 반면에, next는 pre-rendering을 해준다.

 1-2 데이터가 있는 경우

 

페이지 컨텐츠가 외부 데이터에 의존할 경우: getStaticProps를 사용한다.

const Blog = ({ posts }) => {
  return (
    <ul>
      {posts.map((post) => (
        <li>{post.title}</li>
      ))}
    </ul>
  );
};

// getStaticProps를 build time에 불러오기
export async function getStaticProps() {
  // posts를 얻기위해 외부 API를 호출함
  const res = await fetch("https://.../posts");
  const posts = await res.json();

  // { props: { posts } } 형태로 불러옴으로써 Blog 컴포넌트는 build time에 posts를 prop으로서 받게 된다.
  return {
    props: {
      posts,
    },
  };
}

export default Blog;

 

페이지 경로가 외부 데이터에 의존할 경우: getStaticPaths를 사용하는데, 보통 getStaticProps와 함께 사용한다.

function Post({ post }) {
  // Render post
}

// getStaticPaths 함수는, 사전 렌더링 하고싶은 path를
// build time에 특정할 수 있게 해줌
export async function getStaticPaths() {
  // 외부 API 엔드포인트를 불러와서 posts를 얻음
  const res = await fetch("http://.../posts");
  const posts = await res.json();

  // posts에 기반하여, 사전 렌더링하고싶은 path를 얻음
  const paths = posts.map((post) => ({
    params: { id: post.id },
  }));

  // build time에만 이 path들을 (post.id) 사전 렌더링 할 것임
  // { fallback: false }는 다른 라우트는 404를 띄워야 된다는 뜻
  return { paths, fallback: false };
}

export async function getStaticProps({ params }) {
  // params는 post의 id를 포함한다.
  // 라우트가 '/posts/1'의 형태라면 params.id는 1인 것임
  const res = await fetch(`https://.../posts/${params.id}`);
  const post = await res.json();

  // props를 통해 post 데이터를 페이지로 넘긴다.
  return { props: { post } };
}

 

getInitialProps


next.js 공식 문서에서 9.3버전 이후부터는 getStaticProps와 getServerSideProps를 사용하는 것을 더 권장하고 있다.

getInitialProps를 사용할 때, 데이터 초기값을 미리 요청해 컴포넌트에 전달하여 서버 사이드 랜더링이 가능하다.

function Page({ stars }) {
  return <div>Next stars: {stars}</div>
}

Page.getInitialProps = async (ctx) => {
  const res = await fetch('https://api.github.com/repos/vercel/next.js')
  const json = await res.json()
  return { stars: json.stargazers_count }
}

export default Page

처음에는 콘솔이 브라우저에 출력되지만, 새로고침을 하게 되면 값이 터미널에서 출력이 된다.

즉, 초기 렌더링 시에는 서버에서 데이터를 불러오지만, 클라이언트측 내비게이션을 사용하게 되면 클라이언트 측에서 데이터를 불러오는 것을 의미한다.

 

getInitialProps는 Automatic Static Optimization을 지원하지 않는다.

Automatic Static Optimization이란 getServerSideProps 또는 getInitialProps가 페이지 내에 없는 경우에 next.js가 알아서 해당 페이지는 빌드시 html로 만들어주어서 프로젝트 자체가 ssr과 static page가 둘다 제공되는 하이브리드 웹 앱이 될 수 있게 도와주는 것이다. static html로 만들어진 페이지는 cdn을 통해 사용자에게 즉시 스트리밍 할 수 있는 장점을 가진다.
그런데 custom app 컴포넌트 내에서 getInitialProps를 사용할 경우 이 자동 최적화 기능이 off된다.

 

getInitialProps를 사용 할 경우 ssr은 가능하지만 해당 코드가 클라이언트에서도 실행 되어야 하는 상황이 존재 하기 때문에 코드가 브라우저에도 전달 되어야 하고, 해당 영역에서 사용한 모듈이 있으면 또 그만큼 번들 사이즈가 커지게 된다는 점이 있다

 

https://steadily-worked.tistory.com/604#--%--Static%--Generation

 

'JS > react' 카테고리의 다른 글

next에서의 env 설정  (0) 2021.11.29
밸리데이션 체크  (0) 2021.11.29
Next.js - typescript tip  (0) 2021.11.22
Next.js 세팅  (0) 2021.11.19
next 위에서 i18next 적용하기  (1) 2021.11.17
Comments