Linking and Navigating
The default behavior of <Link> is to scroll to the top of a new route or to maintain the scroll position for backwards and forwards navigation.
-> 이렇게 해야 하는 이유는 Link의 특성 때문이다.
페이지 이동 시 스크롤을 맨 위로 올리는 게 Link 컴포넌트의 default scroll behavior이기 때문에,
scroll={false}를 통해 이 default scroll behavior를 override하겠다는 의사를 밝혀야 한다.
id
Link와 목적지 div를 연결해주는 값은 id이다.
예를 들어, Link의 href 속성에 #123이라는 값을 넣어주면,
123이라는 id를 가진 div와 해당 Link가 연결된다.
현재 모든 섹션이 ContentWrapper 컴포넌트 단위로 나뉘어지기 때문에,
Props에 id를 추가해주고 섹션마다 id값을 다르게 전달해주면 된다.
// components/Contents/ContentWrapper.tsx
interface Props {
id: string;
children: React.ReactNode;
style?: string;
}
const ContentWrapper = ({ id, children, style }: Props) => {
return (
<div id={id} className={`min-h-screen px-[200px] py-[200px] ${style}`}>
{children}
</div>
);
};
export default ContentWrapper;
// components/Contents/Main/Main.tsx/* ... */const Main = () => {
return (
<ContentWrapper id="main" style="flex items-center">
<div className="w-full">
<h3 className="mb-6 text-2xl font-light">안녕하세요.</h3>
<SlotMachine textData={textData} />
<h3 className="mt-4 text-4xl font-black">누구누구입니다.</h3>
</div>
</ContentWrapper>
);
};
export default Main;
결과
!https://blog.kakaocdn.net/dn/r2FPw/btspFLjYwZ2/vgpKGFH7LJhZaOPTJQT4fk/img.gif
사실 scroll-behavior: smooth도, text-transform: capitalize도 오늘 처음 알게 된 CSS 속성이다.
JS로 직접 어렵게 구현할 필요 없이 이런 꿀같은 CSS를 활용한다면 시간도 절약되고 성능 면에서도 더 좋을 거라고 생각한다. (내가 만든 기능 vs 전세계의 석학들이 모여 전세계 개발자들을 위해 만든 기능)
아무리 단순한 기능이라도, 이미 구현 방법을 알고 있는 기능이라도 몇 분만 더 투자해서 조금만 더 깊이 검색해본다면 더 좋은 방법, 각 방법의 장단점, 차이점 등 추가로 배울 점이 항상 있다고 생각한다.
다음은 다크 모드 기능을 구현할 것이다.
Next.js Router 정리
Next.js 라우터 사용시 정확한 정의를 모르고 사용하는 부분이 많은 것 같아 자주 사용하는 메서드를 정리해보았습니다.
또한, next.js에서 왜 <Link> 태그를 사용하는지에 대해서도 정리해보았습니다.
Next/Router
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 참고 부탁드립니다.
router.push
client-side 전환을 할 수 있도록 도와주고 Next/link 대신 사용할 수 있습니다.
router.push는 라우터 히스토리 스택에 새로운 url을 쌓아줍니다. 예를 들어 home > login > item 순으로 페이지를 이동했을 때, router.push를 사용해 'mypage'로 이동한다면 라우터 히스토리 스택에는 home > login > item > mypage가 쌓입니다. 마지막 페이지에서 뒤로가기를 누르면 'item' 페이지로 되돌갑니다.
사용법:
router.push(url, as, options)
- url: [필수] 라우팅 하려는 url
- as: [선택] 브라우저 url 바에 보여지는 path
- options: [선택] ]scroll(라우팅 후 스크롤업), shallow, locale 등의 옵션이 있습니다.
주의: 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.replace
router.push와 비슷하게 동작하지만, 라우터 히스토리 스택에 새로운 url을 추가하지 않습니다. 대신 기존에 있던 현재 페이지 route를 새로운 url로 대체합니다.
예를 들어, home > login > item 순으로 페이지를 이동했을 때, router.replace를 사용해 'mypage'로 이동한다면 라우터 히스토리 스택에는 현재 페이지인 item이 mypage로 대체됩니다. 즉, home > login > mypage가 쌓입니다. 마지막 페이지에서 뒤로가기를 누르면 'login' 페이지로 되돌아갑니다.
사용법 (router.push와 동일):
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 vs router.replace 정리
정리하자면, router.push는 라우터의 history 스택 제일 위에 새로운 url을 쌓는 것이고, router.replace는 스택 제일 위에 있는 원소를 새로운 url로 바꾸는 것 입니다.
- 이전의 라우팅 히스토리를 모두 유지하고 싶다면 router.push 를 사용하면 됩니다.
- 만약 현재 라우팅 히스토리를 다른 url로 변경하고 싶다면 (예: 로그인 후 마이페이지 이동했을 때. back 버튼 누르면 다시 로그인 페이지로 가지 않기 위해 로그인 url을 history에서 제거) router.replace를 사용하면 됩니다.
router.back
히스토리에서 전단계로 이동합니다. 브라우저의 '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/Link
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?
Client-side navigation 이란 페이지 전환이 javascript로 이루어지는 것 입니다. 브라우저의 기본 navigation보다 훨씬 빠르게 작동하며, 리액트의 SPA(Single Page Application) 특성을 유지하며 페이지 전환을 할 수 있습니다.
아래 예시에서 보듯이, 페이지 전환을 해도 개발자 도구에서 추가한 style 속성이 새로고침 되지 않습니다. 즉, next.js의 <Link>를 사용하면 전체 페이지를 로드하지 않고, client-side navigation으로 작동합니다.
!https://blog.kakaocdn.net/dn/z4rVw/btspxbX70jU/3eEoLiVTkbkKXWPFNQkZKK/img.gif
만약 <Link> 대신 <a href=".."> 태그를 사용하면, 브라우저가 전체 새로고침을 하기 때문에 링크를 클릭하면 배경화면 색깔이 흰색으로 리셋됩니다.
Code splitting & Prefetching
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 합니다. 링크를 클릭할 때 해당 링크와 연결된 페이지의 코드가 이미 백그라운드에 로드되어 있어, 페이지 전환이 즉시 이루어집니다.
출처:
Link Component - Navigate Between Pages | Learn Next.jsClient-Side Navigation - Navigate Between Pages | Learn Next.jsnext/router | Next.js[React] 코드 스플리팅(Code Splitting) — 오웬의 개발 이야기React Router History : push와 replace의 차이점
'Next.js(ver.13) > Routing' 카테고리의 다른 글
Error Handling (0) | 2023.08.02 |
---|---|
Loading UI and Streaming (0) | 2023.08.02 |
Route Groups (0) | 2023.08.01 |
Pages and Layouts (0) | 2023.08.01 |
Defining Routes (0) | 2023.08.01 |