ISR(Incremental Static Regeneration)
ISR(Incremental Static Regeneration) 을 사용하면 트래픽이 들어올 때 백그라운드에서 다시 렌더링해서
기존 페이지를 업데이트 할 수 있게 해준다. 아래와같이 코드를 작성해보자.
about.js
function About({posts}) {
console.log(posts)
return (
<ul>
{posts.map((post) => (
<li key={post.id}>{post.name}</li>
))}
</ul>
)
}
export default About
export async function getStaticProps(context) {
const res = await fetch(`https://jsonplaceholder.typicode.com/users`)
const posts = await res.json()
return {
props: {
posts,
},
// Next.js will attempt to re-generate the page:
// - When a request comes in
// - At most once every second
revalidate: 1, // In seconds
}
}
실행해보자.
이제 블로그의 포스트리스트는 1초마다 재생성된다. 만약 새로운 블로그 포스트가 추가되면 앱을 재빌드하거나 재배포없이 거의 곧바로 활용가능해진다.
이것은 또한 fallback:true 옵션과 완벽히 동작한다.
Static content at scale
전통적인 SSR과는 다르게 ISR은 정적특징의 장점을 보장해준다.
- 지연시간이 급증하지않고, 페이지는 지속적으로 빠르게 제공된다.
- 페이지가 오프라인이 되지 않으며 만약 재생성이 실패해도 예전 페이지는 변경되지 않고 유지된다.
- db나 백엔드에 로드 부하가 작다. 페이지들이 동시에 한번 재계산되기 때문이다.
파일 읽기 : process.cwd()
파일들을 getStaticProps 에서 직접 파일시스템을 통해 읽혀 질 수 있다. 그러기 위해선 반드시 파일의 full path를 가지고 있어야 한다.
Next.js는 코드를 몇개의 디렉토리 속으로 나누어 컴파일한다. 따라서 __dirname을 사용하면 실제 페이지 디렉토리 경로와 다른 경로를 리턴하기 떄문에 사용할 수 없다.
대신 우리는 process.cwd()를 사용할 수 있다. 이것은 Next.js 실행이 일어나는 디렉토리 정보를 준다.
about.js
import { promises as fs } from 'fs'
import path from 'path'
function About({posts}) {
console.log(posts)
return (
<ul>
{posts.map((post) => (
<li key={post.id}>
<h3>{post.filename}</h3>
<p>{post.content}</p>
</li>
))}
</ul>
)
}
export default About
export async function getStaticProps(context) {
const postsDirectory = path.join(process.cwd(), 'posts')
const filenames = await fs.readdir(postsDirectory)
console.log(postsDirectory)
console.log(filenames)
const posts = filenames.map(async (filename) => {
const filePath = path.join(postsDirectory, filename)
const fileContents = await fs.readFile(filePath, 'utf8')
// Generally you would parse/transform the contents
// For example you can transform markdown to HTML here
return {
filename,
content: fileContents,
}
})
// By returning { props: { posts } }, the Blog component
// will receive `posts` as a prop at build time
return {
props: {
posts: await Promise.all(posts),
},
}
}
이렇게 만들고 posts폴더를 만든 후 abc.txt 파일을 생성해보자.
abc.txt
abc
실행 해보면 아래 화면과 로그를 확인할 수 있다.
posts 폴더 하위에 있는 파일들의 이름과 내용을 찾고 About 컴포넌트로 넘겨주었다.
Write server-side code directly
getStaticProps는 서버사이드에서만 동작한다. 클라이언트 사이드에서는 동작하지 않는다. 또한 브라우저에서 확인 가능한 js bundle에 조차 포함되지 않는다. 이것이 의미하는 것은 direct database queries를 직접 사용해서 정보를 가져올 수 있다는 것이다. getStaticProps로부터 API route를 fetch하면 안된다.
getStaticProps(정적 생성)는 빌드 시 데이터를 가져오고 그곳에서만 처리됩니다. 즉, 프론트엔드와 백엔드가 혼합되지 않습니다. getStaticProps에 데이터가 필요한 경우 데이터를 가져오기 위해 /api에 대한 추가 네트워크 호출을 발생시키지 않아야 합니다. 대신 해당 논리와 함께 함수를 사용하거나 getStaticProps에서 직접 함수를 사용해야 합니다. 프론트엔드에 데이터가 필요한 경우 rest/graphql/whatever/api에서 데이터를 가져오거나 getServerSideProps를 통해 전달할 수 있습니다.
아래 예제를 통해서 js bundle에서 무엇이 제거되는지 확인할 수 있다( 브라우저에서 )
// This app shows what Next.js bundles for the client-side with its new SSG
// support. This editor supports TypeScript syntax.
import Cookies from 'cookies';
import Mysql from 'mysql';
import Link from 'next/link';
import SQL from 'sql-template-strings';
import Layout from '../components/Layout';
const pool = Mysql.createPool(process.env.DATABASE_URL);
export default function ({ projects }) {
return (
<Layout>
<h1>Projects</h1>
<ul>
{projects.map((project) => (
<li key={project.id}>
<Link href="/projects/[id]" as={`/projects/${project.id}`}>
<a>{project.name}</a>
</Link>
</li>
))}
</ul>
</Layout>
);
}
export async function getServerSideProps({ req, res }) {
const userId = new Cookies(req, res).get('user_id');
const projects = await new Promise((resolve, reject) =>
pool.query(
SQL`SELECT id, name FROM projects WHERE user_id = ${userId};`,
(err, results) => (err ? reject(err) : resolve(results))
)
);
return { props: { projects } };
}
// This is the code that is bundled for the client-side:
import Link from 'next/link';
import Layout from '../components/Layout';
export var __N_SSP = true;
export default function ({ projects }) {
return (
<Layout>
<h1>Projects</h1>
<ul>
{projects.map((project) => (
<li key={project.id}>
<Link href="/projects/[id]" as={`/projects/${project.id}`}>
<a>{project.name}</a>
</Link>
</li>
))}
</ul>
</Layout>
);
}
Statically Generates both HTML and JSON
getStaticProps를 가지고 있는 페이지가 빌드 시 pre-render 될 때, Next.js는 HTML파일 뿐 아니라 getStaticProps의 실행 결과인 JSON을 생성한다.
이것은 클라이언트에서 getStaticProps를 호출하는것이 아니라 단지 export된 JSON을 사용한다는 것을 의미한다.
Only allowed in a page
getStaticProps는 page에서만 exported 된다. 다른 곳에서는 사용할 수 없다. 이유는 리액트는 페이지가 render되기 전에 data 모두를 가지고 있어야 하기 때문이다.
또한 반드시 export async function getStaticProps() {}로 동작해야한다.
TypeScript쓸 때는 export const getStaticProps: GetStaticProps = async (context) => {}
Run on every request in development
개발환경에서 getStaticProps는 매 요청시에 호출된다.
Preview Mode
요청시에 페이지가 render 되길 원하는 경우가 생긴다. 배포되기전에 프리뷰 초안을 보길 원할 수 있다.
자세한 내용은 Preview Mode 문서를 참조하자.
'Front-End > Next.js' 카테고리의 다른 글
Next.js | 기본기능 | Data fetching(4) | getServerSideProps (0) | 2021.10.13 |
---|---|
Next.js | 기본기능 | Data fetching(3) | getStaticPaths (0) | 2021.10.13 |
Next.js | 기본기능 | Data fetching(1) (0) | 2021.10.08 |
Next.js | 기본기능 | Pages (0) | 2021.10.08 |
Next.js | 기본기능 | 시작하기 (0) | 2021.10.08 |