ODR(On Demand Revalidation)
getStaticProps
: 빌드 시 최초 한번만 실행 됨. 그래서 데이터가 담긴 HTML이 생성 됨.
아래처럼 revalidate를 쓰면 페이지가 최신인지 아닌지 판단 가능.
nextjs 내부의 타이머가 20초로 맞춰지고, 그 때 까진 모든 사용자에게 같은 페이지를 보여줌. 20초 이후에 방문자가 오면 그 사람에게 역시 같은 페이지를 보여주고, nextjs 내부에서 새 버전의 페이지를 만듦. 그래서 그 다음 방문자에게 새 버전을 보여줌. 역시 로딩이 필요없지.

export async function getStaticProps() {
  console.log("building comming, statically");
  const posts = await client.post.findMany({ include: { user: true } });
  return {
    props: {
      posts: JSON.parse(JSON.stringify(posts)),
    },
    revalidate: 20,
  };
}

아니면 특정 액션 이후에 revalidate를 동작케 할 수 있다. 
api 폴더 내에 revalidate.ts를 만들고 .env에 나만의 TOKEN을 저장한다.
그리고 api/posts에서 post를 작성 할 때, 특정 TOKEN을 포함한 URL로 request를 날려주면
revalidate.ts에서 토큰을 비교해서 revalidate를 해준다.

 

ISR(Incremental Static Regenertion)
그럼 동적인 페이지들도 정적페이지로 만들수는 없을까? (/products/[id] 페이지의 동작방식에서 구현함.)
getStaticPaths에서 paths에 빈 array를 넘기면 됨.
그러면 아래 사진처럼 products폴더 안에 빨간 박스 부분 없이 build됨.
그리고 /products/1로 최초 request가 오면, 1.html을 생성한다.
그 다음 request에는 이미 생성된 HTML을 주게 되니 로딩없이 바로 페이지가 렌더링된다.
이렇게 incremental하게 static 페이지를 generate하는 방식여서 ISR이라고 부른다.


여기서 fallback 옵션을 어떤 것을 주느냐에 따라
페이지를 생성할 동안 사용자에게 어떤 화면을 보여줄지 정할 수 있다.
true,'blocking',false

export const getStaticPaths: GetStaticPaths = () => {
  return {
    paths: [], //페이지 빌드 할 때 아무런 HTML페이지도 미리 생성하지 않는다는 뜻. 그러나 사용자의 요청에 따라 미리 만들어지기 시작할꺼고, 여기서 fallback이 활용된다.
    fallback: true,
    //GetStaticProps or GetStaticPaths이 있는 페이지에 왔을 때, HTML이 아직 없으면,
    //유저를 잠깐 blocking하고 그동안 백그라운드에서 페이지를 만들어서 유저를 줌.
    //blocking 할동안 유저는 아무것도 못보지
    //이는 딱 한번만 일어남. 기본적으로 SSR임.

    //false면 어떤 페이지든 프로젝트의 빌드과정에서 만들어지는 것만이 가질 수 있는것. 추가하지못함
    //그래서 이 경우 404 return됨

    //true면 page generate될 때 까지 무언갈 보여줌
  };
};

1. fallback: true
router에 접근해서 router.isFallbck이라는 변수를 이용해서 페이지 생성 동안 대신 보여줄 html을 지정해준다.

참고로 ISR 이면 위 코드에서 GET방식의 /api/products/ 컨트롤러는 필요 없겠지. 이미 생성된 페이지를 보여주기 때문에. POST는 데이터 변경해야 하기 때문에 필요하고.

2. fallback: false
404 페이지가 리턴됨. 
프로젝트가 build 될 때 생성된 페이지들만 보여준다는 뜻임.

3. fallback: 'blocking'
GetStaticProps or GetStaticPaths이 있는 페이지에 왔을 때, HTML이 아직 없으면,
유저를 잠깐 blocking하고 그동안 백그라운드에서 페이지를 만들어줌.
blocking 할동안 유저는 아무것도 못봄. 이는 딱 한번만 일어남. 기본적으로 SSR임.


참고 할 것들.
ISR은 user의 정보에 의존적인 페이지(account,profile,dashboard 등)에는 적합하지 않음.
사용자별로 페이지를 만들어 놓는게 불가능하니까.
이 때는 그냥 normal fetching을 사용해야 함.

그리고 SSR(getServerSideProps)은 DB가 빠르면 고려해볼만 하다. 다만 blank 페이지를 보게되겠지.




20.7 Code Challenge
community/[id] 부분을 
getStaticProps, getStaticPaths, 그리고 fallback을 사용해서 HTML로 만들어봐.
필요할 때, revalidate도 해야하고.
궁금해요 기능을 위해서 SWR도 해야 함. profile/index에서 사용했었음. 이거 똑같이 하면 됨.

20.0 Introduction

ISR = 단계적 정적 재생성
NextJS에서 최고의 기능!!

페이지를 렌더링하는 방법들
1. CSR - 완성된 초기 html먼저 보여줌, ReactJS가 데이터 알아서 불러오고.
2. SSR - all or nothing, 완성된 HTML 보여주고, ReactJS는 필요없음.(getServerSideProps)
3. 빌드 될 때 파일 미리 생성해두기(getStaticProps, getStaticPath), interaction없는 static page(F&Q 같은 곳)에 사 - 직전 포스트의 내용

이제는 페이지 불러 올 때 getServerSideProps없이도 로딩상태를 완전히  안보여줄 수 있다.


20.1 ISR part One
ISR사용하면 로딩 안보이고, 서버에서 렌더링 할 필요 없음(getServerSideProps사용 안함). 페이지 즉시 불러 올 수 있음.
유저가 페이지 열면 서버단에서 렌더링 되는게 아님. 이미 랜더링 된 상태.

getStaticProps()의 return 객체에 revalidate에 시간(초)을 넣으면
그 시간마다 페이지가 다시 빌드 됨.

export async function getStaticProps() {
  console.log("building comming, statically");
  const posts = await client.post.findMany({ include: { user: true } });
  return {
    props: {
      posts: JSON.parse(JSON.stringify(posts)),
    },
    revalidate: 20,
  };
}
export default Community;

좀더 정확히 말하면,
1. revalidate에는 20초라는 타이머가 설정되고
2. 유저 몇명이 오든 20초 안에 오면 같은 버전의 페이지를 보여줌.
3. 그리고 20초가 지나서 유저가 오면, 여전히 2번의 유저들과 같은 페이지를 보여주지만, 이 때 revalidate를 해서 다시 빌드를 시작한다.
4. 그리고 그 다음에 온 유저는 그 빌드된 새 버전의 페이지를 보게 됨.
즉, revalidate시간이 지나도 사람 안오면 굳이 빌드 안함.
https://nextjs.org/docs/basic-features/data-fetching/incremental-static-regeneration

이를 테스트 해보려면 npm run dev로는 안됨.
개발자 모드이기 때문에 계속 최신 화면 보여주기 때문. 
그러니 npm run build 하고, npm run start해야 함.

19.13 Dynamic getStaticProps

일단 설치

npm i unified remark-parse remark-html

https://www.npmjs.com/package/remark-html

설치하고 아래처럼 사용하면 된다.

import { unified } from "unified";
import remarkParse from "remark-parse/lib";
import remarkHtml from "remark-html";


getStaticPath를 통해 파일 읽고, 파일 이름 읽어서 params에 {slug:name} 객체를 전달한다.
이것들을 페이지로 만들어주세요~하는거지

그러면 getStaticProps에서 context객체를 통해 위 params에 접근 가능하게 되고, 
슬러그 id들을 접수 받고, 이 슬러그(post)들을 HTML로 바꿔주고
화면을 그린다. 아래 사진 참고.

아래는 결과물

 

19.14 Inner HTML
ReacJS는 위처럼 받은 데이터가 html태그여도 그냥String으로 받는다.
보안에 상당히 취약하기 때문이다. 댓글로 <script>태그를 넣어 사용자 정보를 빼올 수도 있다.
그러니 이를 막아놨다.
다만 위 경우, data source를 신뢰 할 수 있기 때문에 dangerouslySetInnerHTML이라는 옵션을 사용하면 된다.
dangerouslySetInnerHTML은 브라우저 DOM에서 innerHTML을 사용하기 위한 React의 대체 방법,__html 키로 객체를 전달한다.

참고, css파일에서 @apply를 사용하면 tailwind 문법 사용가능하다.

19.15 Recap
getStaticProps가 잘 동작하는지 보려면, .next 폴더 지우고 build다시 해야 함.
getStaticProps처럼 페이지 빌드할 때 미리 다 해놓는걸 Backend or CRM or Admin pannel 이라고 부른다(?)

front matter 형식으로 페이지 링크 생성하기.

19.11 getStaticPaths part One

복습차원에서 다시 보면, 
getStaticProps를 이용하여 SSG를 만드는 것은, 
/blog/012-my-first-post에 접속 했을때 이미 모든 데이터가 다 거기 있는 static page(=정적 페이지)라는 것이고,
/products/1에 접속 했을때는 아무것도 없고, API로 product id가 1인 상품의 정보를 DB에서 가져오는 것이다.

번외
es6 기능으로 배열의 원소를 바로 변수로 받아올 수 있음.
해당 안되는것(333)은 무시가능.

 

19.12 getStaticPaths part Two 
getStaticPaths가 필요한 이유?
[slug].tsx라는 파일은 slug가 변수라는 말인데 이 변수가 무한이 될 수 있다.
그런데 우리는 지금 페이지를 미리 만들어 놓는 방식(SSG)을 사용중이다.(getStaticProps를 사용해서.)
next.js 입장에서는 예측 불가능한 수의 페이지들을 만들어 놓는 작업을 막무가내로 시작하기엔 너무 리스키하다. 그래서 getStaticPaths를 사용하라고 에러가 뜬다. 


아래처럼 getStaticPaths를 사용해서 생성할 페이지들을 Next.js에게 알려주면 된다.


getStaticPaths를 보고 모든 slug에 대해 getStaticProps를 실행한다.

build 할때 일어나는 모습

그럼 다음 포스팅에서 이를 화면에 뿌려보자!

19.0 Blog Section
기본적으로 페이지가 서버사이드 렌더링을 하지 않을 때, 또는 API에서 데이터를 가져오지 않을 때, 
그건 누구에게나 정적 코드로 보인다. 데이터는 이미 HTML에 있기 때문.
nextjs는 html을  export해준다. = 빌드될 때 생성된다. 
nextjs로 Markdown 파일(.md)만 써서 블로그 섹션을 만들 수 있다
let's get started!

19.10 getStaticProps
getServerSideProps() 처럼 서버에서 실행된다. 유저의 요청이 발생할 때마다 일어남.
getStaticProps() 딱 한 번 실행 됨.
페이지가 빌드되고 nextjs가 이 페이지를 export 한 후 일반 html로 될 때 실행됨.

front matter = 마크다운 파일에 관련된 데이터를 제공해줌

npm install --save gray-matter

문자열 또는 파일에서 front-matter을 파싱

결과물
코드


build된 file을 보면 짤렸긴 한데 blog에는 SSG라는게 붇는다.
Static Site Generation!



부연설명 - 닉네임 sugar
getStaticProps getStaticProps는 항상 서버에서 실행되고 클라이언트에서는 실행되지 않습니다.
getStaticProps는 정적 HTML을 생성하므로 들어오는 request(예: 쿼리 매개변수 또는 HTTP 헤더)에 액세스할 수 없습니다.
getStaticProps가 있는 페이지가 빌드 시 미리 렌더링되면 페이지 HTML 파일 외에도 Next.js가 getStaticProps 실행 결과를 포함하는 JSON 파일을 생성합니다.
readdireSync() 디렉토리(폴더)의 내용을 읽습니다.
readFileSync() path의 내용을 반환합니다.

이번에는 세션을 어떻게 가져올거냐?
핵심은 NextPageContext

19.6 getServerSideProps

NextJS 데이터 fetching을 어떻게 하나?

유저에게 화면을 어떻게 보여줄지는 두가지로 나뉜다.
1. 다 로딩되면 한번에 보여주자. SSR (server side rendering)
2. 로딩 전에 뭐라도 보여주자. CSR (client side rendering)

1번 방식을 구현하려면 getServerSideProps()를 사용하면된다.
페이지에서 getServerSideProps(서버 측 렌더링)라는 함수를 export 하면 Next.js는 getServerSideProps에서 반환된 데이터를 사용하여 각 요청에서 이 페이지를 미리 랜더링한다고함.

useSWR을 안쓰고 index.tsx에 getServerSideProps()를 다음과 같이 넣어주면
서버에서 먼저 실행한다. 그럼 잘 작동하는데 이 때 useSWR의 다양한 기능을 못씀.
static optimization이나 cache 못함.
그리고 getServerSideProps() 실행 도중 에러나면 아무것도 보지 못한다.

export async function getServerSideProps() {
  const products = await client.product.findMany({});
  console.log(products);
  return {
    props: {
      products: JSON.parse(JSON.stringify(products)),
    },
  };
}

이제, 서버사이드랜더링 + useSWR사용을 알아보자.

19.7 SSR + SWR
위 방식 만으로 prototype
페에지는 SSR로 불러오지만, 클라이언트 단에서 페이지 열릴 때 useSWR이 백그라운드에서 API로 최신 데이터 불러서 업데이트 하는 것.

이 예에서는 getServerSideProps()에서 product의 count를 불러오지 않음.
새로고침 하면 SSR로 한번에 뜨는데
나중에 SWR에서 API로 불러온 product의 count가 업데이트 됨.


여러개도 됨

<SWRConfig
      value={{
        fallback: {
          "/api/products": {
            ok: true,
            products,
          },
        fallback: {
          "/api/user": {
            ok: true,
            products,
          },
        },
      }}
    >
      <Home />
    </SWRConfig>



nextjs는 외부스크립트(SDK같은) 불러 올 때 최적화 해준다.

import Script from "next/script";
그때는 <Script />태그 쓰면 된다.

1. 외부 스크립트 불러오는 방법

<Script src="" strategy="" /> 
beforeInteractive = 페이지를 다 불러와서 상호작용 하기 전에 스크립트 불러옴
afterInteractive = 기본값 = 페이지 다 불러오고 나서 스크립트 불러옴
lazyOnload = 다른 모든 데이터나 리소스 불러오고 나서 스크립트 불러옴, 좋아요가 몇개인지 보려고 페이스북 SDK불러올때 쓰면 좋음

2. 외부 스크립트 로드 됐는지 확인 가능
예를 들어 facebook SDK를 불러오려면 아래 같은 페이지를 마주하게 된다.

외부 스크립트를 불러오려면 여러 지저분한 짓을 했어야 하는데 매우 쉽게 끝낼 수 있다.
onload에 넣으면 된다.

<Script
        src="https://connect.facebook.net/en_US/sdk.js"
        onLoad={() => {
          window.fbAsyncInit = function () {
            FB.init({
              appId: "your-app-id",
              autoLogAppEvents: true,
              xfbml: true,
              version: "v15.0",
            });
          };
        }}
      />

 

+ Recent posts