회사에서
React
만 쓰다보니, 한동안Next
를 잘 사용하지 않았다.
새로 13버전이 나왔다고 해서, 바뀐Next
문법을 정리 해보려고 한다.
Next
12버전에서는 pages/
폴더로 라우팅이 되었는데,
현재 13버전 이후부터는 app/
폴더로 라우팅이 된다고 한다.
13버전은 과도기라서, pages/
, app/
둘다 지원하는 상태이다.
pages/
기반 라우팅은 다음과 같이 이루어진다.
pages/test/index.tsx
-> /test에 라우팅
pages/test/hello.tsx
-> /test/hello에 라우팅
pages/test/[id].tsx
-> /test/~ 에 라우팅
pages/test/[...slug].tsx
-> /test/~, /test/~/~ .. 등에 라우팅
페이지 간 이동은 다음과 같은 방법으로 한다.
useRouter
이용import { useRouter } from 'next/router';
router.push('/test')
router.push({ pathname: '/test', query: { id: 1 } })
Link
이용import Link from 'next/link';
<Link href="/test">페이지 이동</Link>
<Link href={{ pathname: '/test', query: { id: 1 } }}>페이지 이동</Link>
app/
기반 라우팅은 다음과 같이 이루어진다.
app/test/page.tsx
-> /test에 라우팅
app/test/hello/page.tsx
-> /test/hello에 라우팅
app/test/[id]/page.tsx
-> /test/~ 에 라우팅
app/test/[...slug]/page.tsx
-> /test/~, /test/~/~ .. 등에 라우팅
이렇게 모든 파일명이 page.tsx
여야 한다.
추가적으로 layout.tsx
, template.tsx
, error.tsx
, loading.tsx
, not-found.tsx
도 쓸 수 있다.
이 파일들의 기능은 아래 그림과 같다.
컴포넌트로 감쌀 필요 없이, 정해진 파일명으로 파일을 만들면 된다는 것이 신기한 것 같다.
그리고, 중첩 라우팅에서 layout.tsx
등도 같이 중첩 된다.
페이지 간 이동 방식은 앞서 pages/
방식과 동일하다.
React는 기본적으로 클라이언트 사이트 렌더링를 한다.
그래서, 페이지 소스 보기를 누르면 <div id="root"></div>
밖에 안보인다.
Next는 기본적으로 서버 사이드 렌더링을 한다.
그래서 아래와 같이 컴포넌트를 작성한 다음에 페이지 소스를 보면 내용이 나온다.
export default function Home() {
return <div>Test</div>;
}
// 페이지 소스 보기:
// <div>Test</div>
하지만, fetch
, axios
등으로 불러온 데이터는 기본적으로 서버 사이드 렌더링이 안된다.
이를 하려면, Next
12버전에서는 getStaticProps
, getStaticPaths
, getServerSideProps
등을 이용해야 한다.
먼저 getStaticProps
를 살펴 보겠다.
export const getStaticProps: GetStaticProps = async (context) => {
const res = await fetch('https://jsonplaceholder.typicode.com/todos/1');
const data = await res.json();
return {
props: { data },
};
};
getStaticProps
이름을 가진 함수에서,
데이터를 불러온 다음, {props: {data}}
를 반환해주면,
이 파일의 export default
된 컴포넌트의 props
로 data
가 들어온다.
getStaticProps
함수는, 앱 빌드 시 데이터를 미리 가져와서 저장한 다음에
컴포넌트에 뿌려주는 방식으로 작동하기 때문에 속도가 엄청 빠르다.
다음에는 getStaticPaths
를 살펴보겠다.
이는 동적 라우팅인 경우에 getStaticProps
와 같이 사용하는 함수이다.
예를 들어서, [id].tsx
라는 파일에 getStaticPaths
를 사용한다고 가정하겠다.
import { GetStaticProps, GetStaticPaths } from 'next';
export const getStaticPaths: GetStaticPaths = async () => {
return {
paths: [{ params: { id: '1' } }, { params: { id: '2' } }],
fallback: true,
};
};
export const getStaticProps: GetStaticProps = async (context) => {
const res = await fetch(
`https://jsonplaceholder.typicode.com/todos/${context.params?.id}`
);
const data = await res.json();
return {
props: { data },
};
};
동적 라우팅인 경우는, 가능한 라우팅의 개수가 무한개여서 빌드 시 모든 데이터를 미리 저장하는 것이 불가능하다.
그래서, getStaticPaths
를 이용해 무한한 동적 라우팅 중에서, 일부만 선택해서 그것만 미리 빌드하는 것이다.
위 예시는 id
값이 1, 2인 경우만 빌드 시 미리 렌더링하는 경우이다.
이는 getStaticProps
와 같지만, 빌드 시 미리 저장하는 것이 아니라
페이지를 불러오기 직전에 미리 로드하고, 이를 브라우저에 미리 뿌려주는 방식이다.
이를 통해 API 요청 결과의 서버 사이드 렌더링이 가능하다.
export const getServerSideProps: GetServerSideProps = async (context) => {
const res = await fetch(`https://jsonplaceholder.typicode.com/todos/1`);
const data = await res.json();
return {
props: { data },
};
};
next
13에서는 기본적으로 모든 컴포넌트가 서버 사이드 컴포넌트가 된다.
그래서 해당 컴포넌트에서 fetch
로 불러오는 데이터는 모두 서버 사이드 렌더링이 된다.
fetch(URL, { cache: 'force-cache' });
fetch(URL, { cache: 'no-store' });
이렇게 fetch
에 옵션을 줘서 static
처럼 동작하게 할 수도 있다.
하지만 해당 컴포넌트에서, useState
, useEffect
등 훅을 사용하지 못한다.
훅 등은 클라이언트 사이드 컴포넌트에서만 사용해야 한다.
'use client'
export default function Test() {
return <div>Test</div>
}
이러한 클라이언트 사이드 컴포넌트에서 훅을 사용하고,
사버 사이드 컴포넌트에서 import
하는 방식으로 이용해야 한다.
server
컴포넌트와, client
컴포넌트를 적절히 사용하는 능력이 중요할 것 같다.