현재 프론트엔드 엔지니어로, React 만 사용하여도 충분하다고 생각했었습니다.
하지만 날이 갈수록 프론트엔드로써 Next는 필수가 되어가고 있고, 선택이 아닌 필수라는 말이 많습니다.
Next를 사용해보며 왜 이렇게 대세가 되었는지 알아보겠습니다.
기존에 React는 Client-side Rendering입니다. Vue, Angular 또한 CSR 방식으로 이 방법이 대세였습니다.
하지만 지금은 다시 Server-side Rendering 이 다시 유행한다고 합니다.
서버에서 html을 미리 만들어 받아오는 방식입니다.
SSR 을 위해서는 우리가 React에서 밥먹듯이 사용했던, state와 useEffect 등의 사용을 지양하는 것을 권장합니다.
상태관리를 하기에는 좋지만, 그 과정에서는 성능을 저하시킬 수 있기 때문입니다.
원초적 목적은 SSR 이지만 부가기능들도 많습니다.
npx create-next-app@latest
를 입력하게 되면, 프로젝트이름, ts 사용 등 여러 설정을 확인해줍니다.
npm run dev
를 통해서 실행할 수 있습니다.
routing 도 자동으로 되어있습니다.
원하는 폴더를 만들고, 그 안에서 page.tsx 를 만들면 알아서 라우팅 기능이 가능합니다 (신세계다..)
필요한 컴포넌트는 page.tsx 라는 이름이 아니게 만들면, 불러와서 사용할 수 있습니다.
layout.tsx
메인 페이지를 감싸는 용도의 페이지입니다.
next.config.js
nextjs 설정 파일입니다.
이 파일에서 설정할게 많을 예정입니다.
<Image/>
성능과 속도가 중요할 때는 <img/>
가 아닌 <Image/>
태그를 사용합니다.
<Image/>
태그는 다음 기능을 갖습니다.
이미지 렌더링을 최적화 하기 위해, 자동으로 용량을 줄이고, 필요한 장면만 로드하고, 화면 크기에 맞게 조정하는 등의 작업을 수행합니다.
lazy loading
반응형 이미지
이미지 캐싱
이 태그는 몇가지 사용법이 있습니다.
<img/>
태그를 쓰는게 편할 수도 있습니다.next.config.js
/** @type {import('next').NextConfig} */
module.exports = {
images: {
remotePatterns: [
{
protocol: "https",
hostname: "s3.amazonaws.com",
port: "",
pathname: "/my-bucket/**",
},
],
},
};
컴포넌트를 만들 때 페이지 맨 위에 'use client' 라고 한줄만 적으면 그 아래의 모든 컴포넌트는 client component가 됩니다.
그래서 큰 페이지들은 포통 Server Component 로 만들고, JS 기능이 필요한 기능은 Client Component 로 만드는 것이 좋은 습관입니다.
Hook 은 client component 내에서만 사용가능합니다.
useEffect, useState , useRouter 등을 이용하기 위해서는 'use client' 를 이용해야 합니다.
pages 의 api 폴더 안에 원하는 이름의 폴더 안에 + index.ts
파일을 만들어 줍니다.
pages/api/articles/index
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const db = (await connectDB).db("forum");
if (req.method === "GET") {
const list = await getList(db);
return res.status(200).json(list);
}
}
const getList = async (db: any) => {
const list: {
title: string;
content: string;
_id: string;
}[] = await db.collection("post").find().toArray();
return list || [];
};
이렇게 만들면 [GET]api/articles
로 요청을 보내게 되면, getList의 값이 보내집니다.
if (req.method === "POST") {
const result = await db.collection("post").insertOne(req.body);
return res.status(200).redirect("/articles");
}
이번엔 POST 요청으로 보내면, 글을 작성해줍니다.
client component를 이용해서 페이지를 만들게 되면 검색엔진 봇이 페이지를 수집하려고 방문하면 텅빈 html을 보게 됩니다.
검색노출이 중요한 페이지를 만들 때에는, client component로 만들고 버데이터를 가져오는 것이 추천되지 않습니다.
이럴 때에는 부모 server component에서 db 데이터를 가져온 다음 props로 전송하는 방법을 이용합시다.
두개의 차이가 헷갈릴 수 있습니다.
차이점은 언제 html 파일을 생성하는가 입니다.
[정적 생성]
프로젝트가 빌드하는 시점에 html 파일들이 실행됩니다.
모든 요청에 재사용됩니다.
퍼포먼스 이유로, Next js 는 정적 생성을 권고합니다.
정적 생성된 페이지들은 CDN에 캐시됩니다.
getStaticProps
와 getStaticPaths
를 이용해서 사용가능합니다.
[서버사이드 렌더링]
getServerSideProps
유저가 요청하기 전에 페이지가 만들어도 상관없으면 ? => 정적생성
ex ) 도움말 리스트, 제품 목록, 마케팅 페이지, 블로그 페이지 ..
요청이 있을때마다 다시 그려야 한다면 => SSR
사용법에 대해서 알아보겠습니다. 바로 코드로 확인합니다.
const Post = ({item})=>{
return (
<>
<Head>
<title>{item.name}</title>
<meta name="description" content={item.description}></meta>
</Head>
<Item>
{item}
</Item>
<>
)
}
export async function getServerSideProps(context){
const id = context.params.id;
const res = await Axios.get(apiURL)
const data = res.data
return {
props:{
item : data
}
}
}
item을 getServerSideProps 에서 받아와서 보내줍니다.
이 값을 title 과 meta 태그를 통해 보여지게 되면 검색엔진 최적화가 가능해집니다.
=> 공유를 하게 되면, 데이터가 보입니다.
.env.development
, .env.production
파일을 두개 만들어 줍니다.
name = DEV;
NEXT_PUBLIC_API_URL = "http....";
name = PROD;
NEXT_PUBLIC_API_URL = "http....";
사용법은 node.js 와 브라우저 환경에 따라 다릅니다.
node.js
process.env.변수명
브라우저
process.env.NEXT_PUBLIC_변수명
const Home(){
// 브라우저 환경이라서 언더바(_)가 들어감
const API_URL = process.env.NEXT_PUBLIC_API_URL;
...
}
getServerSideProps는 브라우저 환경이 아니라, 서버에서 동작합니다.
window 같은걸 사용하면 에러가 납니다.
export async function getServerSideProps(context) {
const id = context.params.id;
const res = await Axios.get(apiURL);
const data = res.data;
return {
props: {
item: data,
name: process.env.name,
},
};
}
정적 생성은 빌드시에 html을 생성해서, 미리 렌더링된 html을 유저들에게 보내주게 됩니다.
동적 라우팅을 사용할 때, 어떤 페이지를 미리 Static으로 빌드할 지 정하는 api
= pages/[id].tsx
형태의 동적 라우팅 페이지 중, 빌드 시에 static하게 생성할 페이지를 정합니다.
export const getStaticProps = async () => {
return {
path: [
{ params: { id: "1" } },
{ params: { id: "2" } },
{ params: { id: "3" } },
],
fallback: true,
};
};
false
true
blocking
리턴하지 않은 페이지에 접속시
즉 fallback 페이지가 없습니다.
SSR 방식으로 서버 측에서만 실행되고, 브라우저에서 실행되지 않습니다.
페이지 요청시 마다 진행됩니다.
동적으로 데이터를 가져와 업데이트가 가능하다는 장점이 있습니다.
요청시 데이터를 가져와 페이지를 미리 렌더링해야 하는 경우에 사용합니다.
Next.js 는 정말 필요할떄만 사용하라고 합니다.
SSR 방식으로 정적 페이지 생성 방식입니다.
빌드 단계에서만 데이터를 가져오고, JSON 으로 저장해 고정적으로 사용합니다.
페이지 요청 때마다 데이터를 가져오는 것이 아니라서 성능면에서 뛰어납니다.
getStaticProps 와 함께 사용되며, 동적 라우팅이 필요할 때 사용합니다.