
⚠️ 본 포스트는 프로젝트 리펙토링 과정을 담은 개인 기록입니다. Next.js 13 버전의 특징이나 사용법에 대한 학습을 원하신다면, 공식 문서를 참조하시기 바랍니다.
서버 컴포넌트를 사용할 수 있는 next.js@13.4 버전이 정식으로 릴리즈되면서 실무에서 적용된 page router를 app router으로 업그레이드 하기전에 개인 프로젝트에 적용을 해봤다.
next.config.js 파일에 아래 코드를 추가하고 app/경로에 파일을 생성해서 코드를 작성하면 된다
module.exports = {
experimental: {
appDir: true,
},
// Other configuration options
};
기존 Next.js 앱에는 애플리케이션의 모든 페이지와 뷰를 관리하는데 중요한 두 가지구성 요소를 제공한다.
기존 Next.js@12 에서는 특정 라우팅 하위에 레이아웃을 구성하는 것이 불가능했으며, 이로 인해 코드를 중복으로 작성해야 하는 불편함이 있었다.
관련 이슈
공통적으로 사용하는 레이아웃은 _app.jsx 파일이나 _document.jsx 에 적용할 수 있었지만, /main/first /main/second 와 같아 특정 라우트 하위에서 공통 레이아웃을 구성하는 것은 불가능 해서 이로인해 코드의 중복 작성을 해야했다.
그러나 Next.js 13버전 app폴더 구조에서는 이 문제를 해결했다. 특히 layout.tsx을 공유하는 페이지를 탐색할 때 레이아웃이 리렌더링이 되지 않는다. 이를 통해 불필요한 렌더링을 줄이고, 웹 성능을 향상시킬 수 있었다.
- app
📂 main
- layout.tsx
📂 first
- page.tsx
📂 second
- page.tsx
main 세그먼트에 작성된 layout.tsx 파일은 Leaf 세그먼트인 /first 와 /second 에도 영향을 준다. 따라서, 하위 라우트는 모두 <body>{chlidren}</body>안에 구성된다. 이로써, 중복된 레이아웃 코드 작성을 방지하고, 더 효율적인 코드 구조를 만들 수 있게 됐다.
// app/main/layout.tsx
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
next.js@13에서는 모든 컴포넌트가 서버 컴포넌트로 기존에 사용하던 getServerSideProps, getStaticProps 함수가 필요 없어졌다. 그러면 Next 13버전에서는 어떻게 데이터를 가져올까?
fetch API를 사용한다
Next.js 13에서는 fetch 함수에서 cache 옵션과 next 옵션 값을 줘서 SSR, ISR, SSG 와 같은 통신을 구현할 수 있다.

1. SSG
직접 무효화 하기 전까지는 request가 캐싱된다.
빌드 시점에 fetch를 하고 요청 시 캐싱된 데이터를 반환해서 getStaticProps`방식과 비슷하다.
force-cache 옵션은 default 값으로 생략 가능하다.fetch(URL, { cache: 'force-cache' });
2. SSR
매번 요청 때마다 refetch 된다 (getServerSideProps 방식과 비슷하다)
fetch(URL, { cache: 'no-store' });
3. ISR
// 일정 시간 동안만 캐싱
fetch(URL, { next: { revalidate: 20 } });
니콘내콘 프로젝트에서는 데이터를 가져오는 데 SSR, ISR, SSG 세 가지 방법을 모두 사용하고 있었다.
/) : ISR/brand/[id]): SSR/itemList/[id]): ISR (dynamic routes로 getStaticPaths 사용)/items/[id]): SSR메인 페이지에서는 '카테고리 종류' 및 '땡처리 콘' 데이터를 가져오기 위해 두 가지 별도의 통신을 사용하여 데이터를 가져와 화면에 표시하고 있었다. 그러나 화면 상단에 보여지는 카테고리 종류 데이터는 자주 변경되지 않았기 때문에 SSG 방식으로 구현해도 충분했으나, 떙처리 콘 데이터는 자주 변경되는 데이터라 불필요하게 revalidate 값을 설정하여 데이터를 주기적으로 업데이트하고 받아왔다.


위와 같은 문제를 App router의 서버컴포넌트를 도입하면서 페이지 단위가 아닌 컴포넌트 단위로 캐시 전략을 세울 수 있어서 한 페이지에서 통신마다 revalidate속성값을 줄 수 있게 되면서 서버의 부하를 최소화 시켰다.
App router의 서버 컴포넌트를 도입함으로써 페이지 단위가 아닌 컴포넌트 단위로 캐시 전략을 수립할 수 있게 됐다.




App Router로 마이그레이션한 결과, Pages Router 방식에 비해 TTFB가 감소한 것을 확인할 수 있었다. 아래 두 가지 링크에서 비교할 수 있다.
Next.js page router Link : https://ncnc-9ytztvgzd-hyjoong.vercel.app/
Next.js app router Link: https://ncnc.vercel.app/
App Router의 Intercepting Routes을 이용하여, 페이지 이동 시 soft navigation으로 모달 형태로 상세 정보를 표시하고, hard navigation으로 페이지 이동 시 상세 페이지를 보여주도록 구현했다.
