회사에서 진행하는 프로젝트에서 next.js를 본격적으로 사용하는 부분이 생김으로 인해 더 이상 next.js를 무시할 수 없게 되었습니다.
리엑트는 페이스북에서 UI라이브러리라고 소개하고 있지만, 단순 라이브러리라고 하기에는 리엑트를 사용하기 위한 러닝커브가 꽤 가파르고 리엑트에서만 쓰이는 문법또한 존재하므로 라이브러리가 아닌 프레임워크라고 저는 생각합니다.
리엑트에 express
, webpack
과 같은 번들러를 사용해서 충분히 서버사이드 렌더링을 구현할 수 있기에 프레임워크를 위한 프레임워크
를 학습하는데 많은 시간을 투자하지 않았습니다.
리엑트 관련 프로젝트를 진행하면서 SSR이 거의 옵션이 아닌 기본 스펙이 되어버리는 케이스가 많고, 리엑트 서버사이드 렌더링 => nextjs
라는 글들도 많이 보여 nextjs의 학습은 결국 리엑트를 사용하는 프론트엔드 개발자라면 한번은 거쳐야 할 단계라는 생각이 들었습니다.
nextJS는 프론트엔드 프레임워크를 넘어, 자체적으로 api또한 제공할 수 있는 vercel에서 만든 풀스택 프레임워크입니다.
vercel또한 자체 cms 배포 기능등 웹 생태계에 유용한 기능을 많이 제공하고 있음으로 이 회사의 기술을 배우는 것은 장기적으로 이득이 될 것이라고 생각합니다.
리엑트는 자체 라우팅을 제공하지 않음으로 (그래도 여전히 리엑트는 프레임워크라고 생각합니다.)
react-router-dom
, react-router
와 같은 라이브러리를 이용해 클라이언트 사이드 라우팅을 구현합니다.
넥스트는 자체적으로 라우팅 기능을 제공합니다.
pages 폴더는 프로젝트 루트 혹은 src 폴더 아래에 위치할 수 있습니다. pages폴더 안에 있는 파일명이 바로 해당 페이지의 주소가 됩니다.
/notes
주소에서는 pages/notes/index.jsx
파일에서 렌더링하는 페이지가 보이게 됩니다.
/notes/
와 같이 /
로 끝나는 주소가 아닌 params가 붙은 주소가 있습니다.
바로 /notes/1/2
와 같은 경우입니다.
앞선 예제 사진의 디렉토리 처럼
[id].jsx
로 동적 주소를 받을 수 있습니다.
이러한 id는 다음과 같이 next/link
에서 제공하는 useRouter
를 이용해 추출할 수 있습니다.
// [id].jsx
import React from "react";
import { useRouter } from "next/router";
const NoteId = () => {
const router = useRouter();
console.log({ query: router.query, router: router })
return (
<div>Note</div>
)
}
http://localhost:3000/notes/1?can=123
를 요청했을 때,
router 객체를 콘솔에 찍어보면 다음과 같습니다.
asPath: "/notes/1?can=123"
back: ƒ ()
basePath: ""
beforePopState: ƒ ()
components: {/notes/[id]: {…}, /_app: {…}}
defaultLocale: undefined
domainLocales: undefined
events: {on: ƒ, off: ƒ, emit: ƒ}
isFallback: false
isLocaleDomain: false
isPreview: false
isReady: true
locale: undefined
locales: undefined
pathname: "/notes/[id]"
prefetch: ƒ ()
push: ƒ ()
query: {can: "123", id: "1"}
reload: ƒ ()
replace: ƒ ()
route: "/notes/[id]"
[[Prototype]]: Object
[[Prototype]]: Object
위와 같이 [id].jsx
파일을 만듬으로 인해 /notes/1
과 같은 주소에 대한 페이지를 받아볼 수 있었지만, /notes/1/2
와 같이 param이 하나 더 추가 된다면, 해당 페이지는 404에러를 보여줍니다.
몇개의 params가 주소 뒤에 붙을지 모르기 때문에, 모든 params에 대한 페이지 접속을 허가하기 위해서는 catch all routes 기능을 사용할 수 있습니다.
다음의 폴더 구조를 보면 params
가 spread operator를 통해 나타나 있습니다.
[[...params]].jsx
파일은 다음과 같이 되어있습니다.
import React from "react";
import { useRouter } from "next/router";
const Notes = () => {
const router = useRouter();
const { params } = router.query;
console.log({ params })
return (
<div>Note</div>
)
}
export default Notes;
params는 배열 형식으로 router.query
를 통해 뽑아볼 수 있으며, 이름은 params가 아닌 어떤 형태로도 괜찮습니다.
// http://localhost:3000/notes/1/1?can=123 접속 시
params: (2) ["1", "1"]
다시 폴더구조를 살펴보면 [...params]
가 또다른 배열인 []
로 감싸져 있습니다.
pages/notes
경로 아래에 , index.jsx
파일 또한 필요 없습니다. notes 경로 아래에서 일어나는 모든 페이지는 [[...params]].jsx
파일만 수정하면 됩니다.
index.js를 만들면 오류가 생기므로, catch all routes를 사용할 때는 index.js를 사용하지 않도록 조심합시다.
넥스트는 next/link 에서 제공하는 Link
컴포넌트를 이용해 클라이언트 사이드에서의 페이지 네비게이션을 이용할 수 있습니다. 앱 밖에 있는 외부 링크는 기본 html의 a 태그를 사용해야 합니다.
사용법은 간단합니다 react-router의 Link 태그와 비슷합니다.
import React from "react";
import Link from "next/link";
const Page = () => {
return (
<div>
<h1>
IndexPage
</h1>
<Link href="notes" ><a>Note</a></Link>
</div>
)
}
export default Page;
이때 Link 태그 내부를 a태그로 감싸주는 것은 공식 다큐먼트의 권장사항입니다. lint를 사용할 경우 해당 href를 생략했기 때문에 오류를 발생시킴으로, 이 부분에 대한 린트 사용을 해제해야 합니다.
만약 params가 포함된 다른 주소로 이동하기 위해서는 다음과 같이 href와 as 속성을 같이 사용합니다.
const Notes = () => {
const router = useRouter();
const { params } = router.query;
console.log({ params })
return (
<div>
<h1> Note</h1>
<Link href="/notes/[id]" as={`/notes/1`}>note 1</Link>
</div>
)
}
export default Notes;
Link 태그를 제외하고 useRouter()의 리턴 객체를 가지고 프로그래밍을 통해 페이지 네비게이션을 할 수 있습니다. 이 방법은 router.push
를 이용하는 것인데 Link 컴포넌트
와 마찬가지로 클라이언트 사이드 렌더링 환경에서만 작동합니다.
import React from "react";
import Link from "next/link";
import { useRouter } from "next/router";
const Notes = () => {
const router = useRouter();
const { params } = router.query;
console.log({ params })
return (
<div>
<h1> Note</h1>
<Link href="/notes/[id]" as={`/notes/1`}>note 1</Link>
<button onClick={() => router.push("/notes/[id]", "/notes/2")}>note 2</button>
</div>
)
}
export default Notes;
Link 컴포넌트의 as, href 처럼, 첫 인자는 href, 두번째 인자로는 실 경로를 입력합니다.
오늘은 넥스트의 라우팅에 대해 알아보았습니다.
새로운 기술을 배우는 것은 항상 즐겁지만은 않습니다. 하지만 익숙해지면 모든 환경에서 유용하게 사용할 수 있습니다.
항상 배운 것을 복습하시고 실제로 사용해보시길 바랍니다.