Next.js 라우터 사용시 정확한 정의를 모르고 사용하는 부분이 많은 것 같아 자주 사용하는 메서드를 정리해보았습니다.
또한, next.js에서 왜 <Link>
태그를 사용하는지에 대해서도 정리해보았습니다.
Next.js에서 라우터를 사용하려면 useRouter
훅을 사용해서 router
객체에 접근할 수 있습니다. 아래 예시를 보겠습니다.
(참고로, useRouter
는 리액트 훅 이므로 클래스 내부에서 사용 불가합니다.)
import { useRouter } from 'next/router'
function ActiveLink({ children, href }) {
const router = useRouter()
const style = {
marginRight: 10,
color: router.asPath === href ? 'red' : 'black',
}
const handleClick = (e) => {
e.preventDefault()
router.push(href)
}
return (
<a href={href} onClick={handleClick} style={style}>
{children}
</a>
)
}
export default ActiveLink
라우터에서 자주 사용하는 메서드입니다: router.push
, router.replace
, router.prefetch
, router.beforePopState
, router.back
, router.reload
, router.events
.
이중에서 가장 헷갈렸던 router.push, router.replace의 차이점과 자주 사용하는 router.back 정도만 정리해보겠습니다. 자세한 설명은 공식 도큐 next/router | Next.js 참고 부탁드립니다.
client-side 전환을 할 수 있도록 도와주고 Next/link 대신 사용할 수 있습니다.
router.push는 라우터 히스토리 스택에 새로운 url을 쌓아줍니다. 예를 들어 home > login > item 순으로 페이지를 이동했을 때, router.push를 사용해 'mypage'로 이동한다면 라우터 히스토리 스택에는 home > login > item > mypage가 쌓입니다. 마지막 페이지에서 뒤로가기를 누르면 'item' 페이지로 되돌갑니다.
router.push(url, as, options)
주의: router.push
는 외부 url 사용시에는 적합하지 않습니다. a tag의 target="_blank" 를 사용하거나 window.location을 사용하는 것이 낫습니다.
import { useRouter } from 'next/router'
export default function Page() {
const router = useRouter()
return (
<button type="button" onClick={() => router.push('/about')}>
Click me
</button>
)
}
router.push와 비슷하게 동작하지만, 라우터 히스토리 스택에 새로운 url을 추가하지 않습니다. 대신 기존에 있던 현재 페이지 route를 새로운 url로 대체합니다.
예를 들어, home > login > item 순으로 페이지를 이동했을 때, router.replace를 사용해 'mypage'로 이동한다면 라우터 히스토리 스택에는 현재 페이지인 item이 mypage로 대체됩니다. 즉, home > login > mypage가 쌓입니다. 마지막 페이지에서 뒤로가기를 누르면 'login' 페이지로 되돌아갑니다.
router.replace(url, as, options)
import { useRouter } from 'next/router'
export default function Page() {
const router = useRouter()
return (
<button type="button" onClick={() => router.replace('/home')}>
Click me
</button>
)
}
정리하자면, router.push
는 라우터의 history 스택 제일 위에 새로운 url을 쌓는 것이고, router.replace
는 스택 제일 위에 있는 원소를 새로운 url로 바꾸는 것 입니다.
router.push
를 사용하면 됩니다.router.replace
를 사용하면 됩니다.히스토리에서 전단계로 이동합니다. 브라우저의 'back'버튼을 누르는 것과 동일하게 동작합니다.
window.history.back()
와 같이 동작합니다.
import { useRouter } from 'next/router'
export default function Page() {
const router = useRouter()
return (
<button type="button" onClick={() => router.back()}>
Click here to go back
</button>
)
}
Next.js에서는 a tag 대신, <Link>
컴포넌트를 사용해 a tag를 감싸줍니다. <Link>
를 사용하면 클라이언트 사이드 네비게이션(client-side navigation)을 할 수 있도록 도와줍니다.
import Link from 'next/link'
<h1 className="title">
Read{' '}
<Link href="/posts/first-post">
<a>this page!</a>
</Link>
</h1>
Client-side navigation 이란 페이지 전환이 javascript로 이루어지는 것 입니다. 브라우저의 기본 navigation보다 훨씬 빠르게 작동하며, 리액트의 SPA(Single Page Application) 특성을 유지하며 페이지 전환을 할 수 있습니다.
아래 예시에서 보듯이, 페이지 전환을 해도 개발자 도구에서 추가한 style 속성이 새로고침 되지 않습니다. 즉, next.js의 <Link>
를 사용하면 전체 페이지를 로드하지 않고, client-side navigation으로 작동합니다.
만약 <Link>
대신 <a href="..">
태그를 사용하면, 브라우저가 전체 새로고침을 하기 때문에 링크를 클릭하면 배경화면 색깔이 흰색으로 리셋됩니다.
React를 빌드/배포하면 기본적으로 모든 js, css 파일이 하나의 파일로 번들링되며 하나의 큰 파일이 됩니다. 따로 webpack 설정을 해주지 않는다면, 특정 페이지에 필요없는 다른 파일들까지 번들링 되기 때문에 파일이 커지면 성능에 문제가 될 수도 있습니다. 또한, 한 줄의 js 코드만 수정해도 모든 JS코드를 새로 빌드해야하기 때문에 비효율적입니다. 따라서, 파일을 분리하는 작업인 '코드 스플리팅'을 하는 것이 효율적입니다.
예를 들어 페이지가 /main, /about, /post 이렇게 세 가지 페이지로 이루어진 SPA를 개발한다고 할 때 /main 페이지를 들어가는 동안 /about이나 /post 페이지 정보는 사용자에게 필요하지 않을 확률이 높다. 그러한 파일들을 분리하여 지금 사용자에게 필요한 파일만 불러올 수가 있다면 로딩도 빠르게 이루어지고 트래픽도 줄어 사용자 경험이 좋아질 수가 있다. 이와 같이 더 나은 사용자 경험을 위해 코드를 비동기적으로 로딩하는 방법이 있는데 코드 비동기 로딩의 대표적인 예시가 바로 코드 스플리팅이다. 출처: [React] 코드 스플리팅(Code Splitting) — 오웬의 개발 이야기
다행히도, Next.js는 자동으로 코드 스플리팅을 해주므로 각 페이지에 필요한 항목만 로드합니다. 즉, 메인 페이지를 렌더링 하면, 다른 페이지의 코드는 처음에 제공되지 않습니다. 덕분에 수백개의 페이지가 있어도 원하는 페이지 (ex. 메인 페이지) 로드를 빠르게 할 수 있습니다.
요청한 페이지만 로드되므로 다른 페이지들과 분리됩니다. 따라서 특정 페이지에 오류가 발생해도 나머지 애플리케이션을 정상적으로 작동합니다.
또한 'Next.js'의 프로덕션 빌드에서 <Link>
요소가 브라우저의 뷰포트에 나타날 때마다, Next.js는 백그라운드에서 연결된 페이지의 코드를 자동으로 prefetch 합니다. 링크를 클릭할 때 해당 링크와 연결된 페이지의 코드가 이미 백그라운드에 로드되어 있어, 페이지 전환이 즉시 이루어집니다.