SSG,SSR,CSR,ISR 존재함
파일 내부에서 컴포넌트 외 구현하는 함수나 해당 반환값에 따라 렌더링 방법이 달라짐. 각 페이지들이 어떤 타입을 설정 돼 있는지 빌듯시 결과로 확인 할 수 있음.
렌더링방식을 결정하는 주요한 요소는 데이터 취득 함수임.
종류 | 데이터취득시 사용함수 | 데이터 취득시점 | 비고 |
---|---|---|---|
SSG | getStaticProps | 빌드시 | 데이터 취득 함수를 사용하지 않는 경우도 SSG임 |
SSR | getServerSideProps | 사용자요청시 | getInitialProps를 사용해도 SSR |
ISR | revalidate를 반환하는 getStaticProps | 빌드시 | 배포후에도 백그라운드 빌드진행 |
CSR | useEffect, useSWR... | 사용자요청시(브라우저) | ISR/SSG/SSR와 동시사용가능 |
페이지는 getStaticProps가 반환한 props를 받을 수 있다.(없을수도 있음)
getStaticProps는 비동기함수로 async와 함께 정의해야함.
인수에는 context가 존재함. => 빌드시에 사용할 수 있는 데이터가 포함됨.
import { GetStaticProps, NextPage, NextPageContext } from "next";
import Head from "next/head";
// 페이지 컴포넌트인 props의 타입 정의
type SSGProps = {
message: string;
};
// SSG는 getStaticProps가 반환한 props를 받을 수 있다
// NextPage<SSGProps>는 Message: string 만을 받아 생성된 페이지 타입
// Next.js의 페이지 컴포넌트나 함수 타입은 https://nextjs.org/learn/excel/typescript/nextjs-types도 참고한다
const SSG: NextPage<SSGProps> = (props) => {
const { message } = props;
return (
<div>
<Head>
<title>Static Site Generation</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<main>
<p>이 페이지는 정적 사이트 생성을 통해 빌드 시 생성된 페이지입니다.</p>
<p>{message}</p>
</main>
</div>
);
};
// getStaticProps는 빌드에 실행된다
// GetStaticProps<SSGProps>는 SSGProps인수로 받는 getSTaticProps 타입
export const getStaticProps: GetStaticProps<SSGProps> = async (context) => {
const timestamp = new Date().toLocaleString();
const message = `${timestamp}에 getStaticProps가 실행되었습니다`;
console.log(message);
return {
// 여기에서 반환한 props를 기반으로 페이지 컴포넌트를 그린다
props: {
message,
},
};
};
export default SSG;
데이터가 다른 여러개의 페이지를 만들 때 동적라우팅 기능을 사용가능함.
[id].tsx와 같이 대괄호로 감싼 파일이거나
getStaticProps에 맞춰 getStaticPaths를 사용할 수 있음
getStaticPaths는 getStaticProps 실행전에 호출되는 함수로, 생성팔 페이지의 경로 파라미터의 조합
아래 코드에서는 id가 1,2,3인 경로파라미터를 반환함 => /post/1, /post/2, /post/3 이렇게 생성함.
fallback을 false로 반환하면 path에 주어지지 않은 경로에 대해서는 404를 뱉는다. fallback true라면, 최초요청과 그 뒤 요청에서 동작방식이 달라짐.
12버전에서의 Image 컴포넌트는 next/legacy/image로 사용가능. (13버전 사용권장) => span으로 감싸서 image position을 결정하는 방식
// 타입을 사용하기 위한 임포트
import { GetStaticPaths, GetStaticProps, NextPage } from 'next'
import Head from 'next/head'
import { useRouter } from 'next/router' // next/router에서 useRouter라는 훅을 삽입한다
import { ParsedUrlQuery } from 'querystring'
type PostProps = {
id: string
}
const Post: NextPage<PostProps> = (props) => {
const { id } = props
const router = useRouter()
if (router.isFallback) {
// 폴백 페이지용 표시를 반환한다
return <div>Loading...</div>
}
return (
<div>
<Head>
<title>Create Next App</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<main> <p> 이 페이지는 정적 사이트 생성을 통해 빌드 시 생성된 페이지입니다.
</p>
<p>{`/posts/${id}에 대응하는 페이지입니다`}</p>
</main>
</div>
)
}
// getStaticPaths는 생성한 페이지의 경로 파라미터의 조합을 반환한다
// 이 파일은 pages/posts/[id].tsx이므로, 경로 파라미터로서 id의 값을 반환해야 한다
export const getStaticPaths: GetStaticPaths = async () => {
// 각 페이지의 경로 파라미터를 모은 것
const paths = [
{
params: {
id: '1',
},
},
{
params: {
id: '2',
},
},
{
params: {
id: '3',
},
},
]
// fallback을 false로 설정하면, paths에 정의된 페이지 아래는 404를 표시한다
return { paths, fallback: false }
}
// 파라미터 타입을 정의
interface PostParams extends ParsedUrlQuery {
id: string
}
// getStaticPaths 실행 후에 각 경로에 대해 getStaticProps가 실행된다
export const getStaticProps: GetStaticProps<PostProps, PostParams> = async (context) => {
return {
props: {
id: context.params!['id'],
},
}
}
export default Post
SSR : getSeverSideProps 호출
ISR : revalidate를 반호나하는 getStaticProps를 호출
가장 처음으로 페이지에 접근한 경우에는 SSG의 경우와 마찬가지로 fallback페이지를 표시함. 이후에 요청에서는 revalidate 지정한 시간내에는 같은 페이지를 반환함.
유효기간 이후에는 현재 저장되있는 페이지에 getStaticProps를 재 호출해 새로운 캐시로 저장함.
import { GetStaticPaths, NextPage, GetStaticProps } from 'next'
import Head from 'next/head'
import { useRouter } from 'next/router'
type ISRProps = {
message: string
}
// ISRProps를 받는 NextPage(페이지) 타입
const ISR: NextPage<ISRProps> = (props) => {
const { message } = props
const router = useRouter()
if (router.isFallback) {
// 폴백용 페이지를 반환한다
return <div>Loading...</div>
}
return (
<div>
<Head>
<title>Create Next App</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<main>
<p>이 페이지는 ISR을 통해 빌드 시 생성된 페이지입니다.</p>
<p>{message}</p>
</main>
</div>
)
}
export const getStaticProps: GetStaticProps<ISRProps> = async (context) => {
const timestamp = new Date().toLocaleString()
const message = `${timestamp}에 이 페이지의 getStaticProps가 실행되었습니다`
return {
props: {
message,
},
// 페이지의 유효 기간을 초단위로 지정한다
revalidate: 60,
}
}
export default ISR
Link 컴포넌트는 CSR방식으로 동작함. 새로운 페이지를 그리기 위한 데이터는 미리 비동기 방식으로 얻는다.
a태그를 Link태그로 감싸거나 버튼을 감싸는 형태로 사용
router.push를 통해 이동가능함 + 쿼리스트링 지정가능
img태그가 아니라 Image 컴포넌트를 사용해서 이미지를 읽을 때 서버사이드에서 이미지를 최적화함.
Image 컴포넌트에 width, height를 전달하지 않으면 에러 발생함.
img 태그와 마찬가지로 src에 이미지 경로를 전달하는데, 로컬 이미지에 대해서는 import한 이미지파일을 src에 부여가능(이때 width, height 생략가능함)
브라우저의 정보를 기반으로 최적화환 이미지를 제공함. => Webp대응 브러우저에서는 WebP형식을 제공하거나, 브라우저 화면 크기에 맞춰 적절한 이미지를 제공하기도 함.
prop을 받을 수 있음
layout을 조절하는 prop, 이미지 로딩중에 표시할 컨텐츠인 placeholder등이 존재
외부 이미지 같은 경우, next.config.js domains에 최적화를 허가하는 이미지의 도메인을 추가하거나, Image 컴포넌트의 unoptimzed에 true를 전달해 최적화를 무효화해야함.
Next Image 컴포넌트는 WebP 타입의 이미지를 다운로드함. => 일반적인 jpg보다 용량이 훨씬 작다.
Next Image를 사용하면 서버에서 자동으로 최적화를 진행해줌, quality 속성을 통해 얼마나 최적화 할지도 결정 할 수 있음. + lazy loading도 자동으로 설정됨.
PlaceHolder blur 옵션을 설정하면 사진이 다운로드 되는 동안 블러이미지가 자동으로 적용됨.
Next에서 최적화를 가능한 이유는 => 파일을 static하게 import했기 때문 => 빌드시에 미리 width height 값을 알 수 있다.
만약 외부링크로 가져올때는 width, height를 미리 알 수 없음 => fill 이라는 속성을 사용해서 이를 해결가능함.
이 경우 부모컴포넌트의 사이즈에 따라 Image Size가 결정됨, object fit속성을 같이 사용한다.
외부링크 자체를 사용 할 수 없는경우 => next.config 설정을 변경해주어야 한다.
외부 API를 이용가능하게 해주는 컴포넌트임
https://nextjs.org/docs/pages/api-reference/components/script
onLoad, onReady와 같이 script가 성공적으로 호출되었을 때 실행가능하게 해주는 callback prop들이 존재함.
onLoad => 스크립트가 처음 불러와 졌을때만 실행됨, onReady => script가 성공적으로 실행되었을때 실행됨.
Strategy라는 속성존재 => loading 하는방식을 정의함.
afterInteractive(default) : 페이지가 hydration이 성공하자마자 script를 로드함.
beforeInteractive : 페이지 하이드레이션 전에 script를 가져옴. 페이지 하위의 다큐먼트 파일 즉 전역적으로 사용할 때 사용을 권장.
lazyOnload : script 필요시에 로딩함.
pages/api 아래에 놓인 파일에서는 API(JSON 기반의 Web API) 를 정의함.
빌드시에는 이 API를 사용할 수 없음(getStaticPaths, getStaticProps로부터 호출 불가)
import type { NextApiRequest, NextApiResponse } from 'next'
type HelloResponse = {
name: string
}
// /api/hello에서 호출되었을 때의 API 동작을 구현한다
export default (req: NextApiRequest, res: NextApiResponse<HelloResponse>) => {
// 상태 200으로 {"name": "John Doe"}를 반환한다
res.status(200).json({ name: 'John Doe' })
}
.env 파일 내부적으로 처리가능 => .env, .env.local, .env.{환경명}.local
local이 붙은것은 .gitignore에 추가되는 것을 의도한 것으로 api 키 등 공개하고 싶지 않은 값을 저장하기 위해 사용함.
.env.development , .env.development.local은 개발환경의 환경변수로 사용함.
.env.production, .env.production.local은 프로덕션 환경에서의 환경변수로 사용함.
로딩된 환경변수는 서버사이드에서 실행하는 처리에 참조 할 수 있음. 클라이언트 사이드에서도 접근 하고 싶은 값에는 NEXTPUBLIC 을 붙힙니다.
import { NextPage, GetStaticProps } from 'next'
import Head from 'next/head'
const EnvSample: NextPage = (props) => {
// 서버 사이드에서 그릴 때는 'test1'라 표시되고, 클라이언트 사이드에서 다시 그릴 때는 undefined로 표시된다
console.log('process.env.TEST', process.env.TEST)
// 'test2'라 표시된다
console.log('process.env.NEXT_PUBLIC_TEST', process.env.NEXT_PUBLIC_TEST)
return (
<div>
<Head>
<title>Create Next App</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<main>
{/* 서버 사이드에서 그릴 때는 'test1'이라 표시되고, 클라이언트 사이드에서 다시 그릴 때는 아무것도 표시되지 않는다 */}
<p>{process.env.TEST}</p>
{/* test2가 표시된다 */}
<p>{process.env.NEXT_PUBLIC_TEST}</p>
</main>
</div>
)
}
// getStaticProps는 항상 서버 사이드에서 실행되므로, 모든 환경 변수를 참조할 수 있다
export const getStaticProps: GetStaticProps = async (context) => {
// 'test1'가 표시된다
console.log('process.env.TEST', process.env.TEST)
// 'test2'가 표시된다
console.log('process.env.NEXT_PUBLIC_TEST', process.env.NEXT_PUBLIC_TEST)
return {
props: {
},
}
}
export default EnvSample