라우팅
<Link>
컴포넌트
- Next.js에서는 링크를 연결하는데
<a>
태그 대신에 <Link>
컴포넌트를 사용함
<a
> 태그를 사용하면 페이지를 이동할 때 페이지 전체를 다시 로딩하기 때문에 속도가 느리고, 빈 화면이 잠깐 보이면서 깜빡거림이 생김
<Link>
컴포넌트는 Next.js에서 내부적으로 여러 가지 최적화를 해주기 때문에 빠르고 부드러운 페이지 전환이 가능함
import Link from 'next/link';
export default Page() {
return <Link href="/">홈페이지로 이동</Link>;
}
useRouter()
Hook
쿼리 사용하기
router.query
값을 사용하면 페이지 주소에서 Params 값이나 쿼리스트링 값을 참조할 수 있음
- 예를 들면
pages/products/[id].js
페이지에서 router.query['id']
값으로 Params id
에 해당하는 값을 가져올 수 있음
import { useRouter } from 'next/router';
export default function Product() {
const router = useRouter();
const id = router.query['id'];
return <>Product #{id} 페이지</>;
}
/search?q=티셔츠
와 같은 주소로 들어왔을 때 router.query['q']
값으로 쿼리스트링 q에 해당하는 값을 가져올 수 있음
import { useRouter } from 'next/router';
export default function Search() {
const router = useRouter();
const q = router.query['q'];
return <>{q} 검색 결과</>;
}
페이지 이동하기
router.push()
함수를 사용하면 코드로 페이지를 이동할 수 있음
import { useState } from 'react';
import { useRouter } from 'next/router';
export default function SearchForm() {
const [value, setValue] = useState();
const router = useRouter();
function handleChange(e) {
setValue(e.target.value);
}
function handleSubmit(e) {
e.preventDefault();
if (!value) {
return router.push('/');
}
return router.push(`/search?q=${value}`);
}
return (
<form onSubmit={handleSubmit}>
<input name="q" value={value} onChange={handleChange} />
<button>검색</button>
</form>
);
}
리다이렉트
next.config.js
파일을 수정하면 특정 주소에 대해서 리다이렉트할 주소를 지정할 수 있음
- 예를 들어서
/products/:id
라는 주소로 들어오면 /items/:id
라는 주소로 이동시켜 줄 수 있음
- 이때
permanent
라는 속성으로 상태 코드를 정할 수 있는데 permanent: false
로 하면 307 Temporary Redirect를 하고, permanent: true로 하면 브라우저에 리다이렉트 정보를 저장하는 308 Permanent Redirect를 할 수 있음
const nextConfig = {
async redirects() {
return [
{
source: '/products/:id',
destination: '/items/:id',
permanent: true,
},
];
},
}
module.exports = nextConfig;
커스텀 404 페이지
- 존재하지 않는 주소로 들어올 경우에 Next.js에서는 기본적으로 404 페이지를 보여 줌
- 내가 원하는 404 페이지를 보여주려면
pages/404.js
파일을 만들고 일반적인 페이지처럼 구현하면 됨
커스텀 App
- 모든 페이지에 공통적으로 코드를 적용하고 싶다면 커스텀 App 컴포넌트를 수정하면 됨
pages/_app.js
파일에 있는 컴포넌트인데 이 컴포넌트에 사이트 전체에서 보여 줄 컴포넌트나 전체적으로 적용할 리액트 컨텍스트를 적용할 수 있음
- 사이트 전체에 적용할 CSS 파일도 여기서 임포트할 수 있음
- 커스텀
App
컴포넌트의 Props는 Component
와 pageProps
가 있는데 우리가 만든 페이지들이 Component
Prop으로 전달되고 여기에 내부적으로 필요한 Props는 pageProps
라는 값으로 전달됨
커스텀 Document
pages/_document.js
파일에 있는 Document
컴포넌트는 HTML 코드의 뼈대를 수정하는 용도로 사용함
- 코드는 React 컴포넌트이지만 일반적인 컴포넌트처럼 동작하지는 않기 때문에
useState
나 useEffect
처럼 브라우저에서 실행이 필요한 기능들은 사용할 수 없음
import { Html, Head, Main, NextScript } from 'next/document'
export default function Document() {
return (
<Html lang="ko">
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
사이트 완성하기
<Image>
컴포넌트
- Next.js에서는 이미지를 사용할 때 Next.js 서버를 한 번 거쳐서 이미지 최적화를 한 다음 사용할 수 있도록 해 줌
- 그래서 되도록이면
<img>
태그보다는 <Image>
컴포넌트를 사용하는 걸 권장함
<Image>
컴포넌트는 next/image
에서 불러와서 사용함
- 이때 반드시 크기가 있어야 하는데
width
와 height
값을 지정하거나 또는 fill
이라는 Prop을 사용할 수 있음
width와 height를 사용하는 경우
import Image from 'next/image';
export default function Page() {
return (
<>
<Image
src="/images/product.jpeg"
width={300}
height={300}
alt="상품 이미지"
/>
</>
);
}
fill을 사용하는 경우
- 이미지 크기를 유연하게 지정해야 할 때는
fill
을 사용gka
- 이때 부모 요소에서
position: relative
와 같이 포지셔닝해야 함
fill
을 사용할 경우 absolute
포지션으로 배치되기 때문에, "가장 가까운 포지셔닝이 된" 조상 요소에 꽉 차도록 이미지가 배치됨
- 만약 이미지의 비율이 깨지는 것을 막고 싶다면
object-fit: cover
속성으로 이미지를 크롭하면 됨
import Image from 'next/image';
export default function Page() {
return (
<>
<div
style={{
position: 'relative',
width: '100%',
height: '300px',
}}
>
<Image
src="/images/product.jpeg"
fill
alt="상품 이미지"
style={{
objectFit: 'cover',
}}
/>
</div>
</>
);
}
<Head>
컴포넌트
next/head
에서 불러와서 <Head>
컴포넌트 안에 <head>
태그에 넣고 싶은 코드를 작성하면 됨
import Head from 'next/head';
export default function Page() {
return (
<>
<Head>
<title>페이지 제목</title>
<link rel="icon" href="/favicon.ico" />
</Head>
...
</>
);
}
- 만약 사이트 전체에 공통으로 적용하고 싶다면 /pages/_app.js 파일에서
<Head>
컴포넌트를 활용하면 됨
import Head from 'next/head';
export default function App({ Component, pageProps }) {
return (
<>
<Head>
<title>사이트 기본 제목</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<Component {...pageProps} />
</>
);
}
구글 폰트 적용하기
- Next.js에서는 구글 폰트를 위한 기능도 제공함
- 구글 폰트를 편하게 쓰는 것뿐만 아니라 여러 가지 최적화도 함께 제공함
- subsets는 폰트에서 영문, 한글 이런 식으로 사용할 글자들만 골라서 사용할 때 쓰는 건데, 만약에 영문만 사용하는 폰트라면
['latin']
과 같이 써 주면 됨
import { Noto_Sans_KR } from '@next/font/google';
const notoSansKR = Noto_Sans_KR({
weight: ['400', '700'],
subsets: [],
});
- 폰트를 적용하려면 notoSansKR 객체의 className 프로퍼티를 사용할 수 있음
<main className={notoSansKR.className}>
...
</main>
- 아니면 Next.js에서 제공하는 Head 컴포넌트를 활용해서 전역 스타일로 적용할 수도 있음
<Head>
<style>{`
html {
font-family: ${notoSansKR.style.fontFamily}, sans-serif;
}
`}</style>
</Head>
- 폰트를 적용하고 개발자 도구를 열어서 Network 탭의 세부 탭인 Font 탭을 살펴보면 구글 사이트가 아니라, 우리 사이트에서 폰트 파일을 받아 오는 걸 알 수 있는데 그래서 초기 로딩 속도가 훨씬 빨라지는 것임
개발모드, 빌드, 실행 그리고 배포
개발 서버 켜기
- 프로젝트 폴더에서 터미널을 연 다음, 아래 명령을 입력해서 개발 서버를 실행할 수 있음
- 개발 모드이기 때문에 새로고침 없이도 수정 사항을 그때 그때 확인할 수 있음
npm run dev
빌드하기
- Next.js 프로젝트를 배포하려면 우선 실행 가능한 형태로 코드를 변환한 다음에, 서버에서 실행을 해야 함
- 이때 코드를 변환하는 과정을 "빌드"라고 함
- 빌드를 하려면 프로젝트 폴더에서 터미널을 연 다음, 아래 명령어를 입력하면 됨
npm run build
- 그럼 .next 폴더에 실행에 필요한 파일들이 생성됨
실행 하기
- 프로젝트를 빌드했다면 이제 실행할 수 있음
- 마찬가지로 프로젝트 폴더에서 터미널을 연 다음, 아래 명령어를 입력하면 됨
npm run start
배포하기
- Vercel(https://vercel.com/)이라는 서비스를 이용하면 Next.js 프로젝트를 간편하게 배포할 수 있음
- GitHub 리포지토리와 연동해 놓으면, 리포지토리가 업데이트될 때마다 빌드와 실행 과정을 Vercel이 알아서 수행함