
Next.js의 useRouter 를 활용하면
Home 화면에서 각각의 detail 한 상품 (위 움짤에서는 movie) 페이지로 넘어갈 때 ,
URL 의 query string으로 데이터를 넘겨주면서 유저가 보는 URL에는 해당 내용들이 보이지 않도록 숨길 수 있다.
이렇게 하면 Home 화면에서 이미 받아온 데이터를 재활용하는 것이기 때문에 detail 페이지에 접속할 때 api 요청으로 데이터를 다시 받아오는 것보다 빠르게 렌더링할 수 있다
하지만 Home 화면 접속 후 → Detail 페이지로 들어갔을 때에만 데이터를 넘겨 받아올 수 있으므로, 시크릿 창에서(캐시 없이) Detail 페이지로 바로 접속하는 경우 렌더링할 데이터가 없게 된다.
Next.js의 페이지 이동하는 방법에는 2가지가 있다.
1. Link 컴포넌트
2. useRouter의 .push() 메서드
두 방법에서 모두 url의 query string 으로 데이터를 넘겨줄 수 있다.
<Link > 컴포넌트import Link from 'next/link'
<Link
href = {{
pathname: '이동하려는 주소',
query: { /* 넘기려는 데이터를 객체로 작성 */ },
}}
as = '유저에게 보여줄 주소'
> 페이지 이동 버튼 </Link>
Link 컴포넌트의 props 로 href 와 as 속성을 넣는다.
href 에는 pathname 과, query 프로퍼티가 있다.pathname : 이동하려는 주소query : 전달하려는 데이터를 key, value 로 작성한다. useRouter의 query 메서드로 꺼내 쓸 수 있다.as 에는 화면에 보여줄 url 의 query string 을 작성한다./movies/123?title=스파이더맨&rate=1 이렇게 길어지게 된다.href = {{ pathname: '/movies/123', query : { title: '스파이더맨', rate: 1 }` }}// /pages/index.js
import Image from 'next/image'
import Link from 'next/link'
import axios from '@/api/axios'
// 서버 사이드 렌더링으로 movies 데이터를 받아옴
export const getServerSideProps = async () => {
const { data } = await axios.get('/popular?language=en-US&page=1')
return { props: { movies: data.results } }
}
export default function Home({ movies = [] }) {
return (
<div className='container'>
{movies?.map(movie => (
<Link
key={movie.id}
href={{
pathname: `/movies/${movie.id}`, // 실제 이동할 페이지 URL
query: { // query string으로 넘겨줄 데이터
title: movie.original_title,
poster: `https://image.tmdb.org/t/p/w500/${movie.poster_path}`,
},
}}
as={`/movies/${movie.id}`} // 주소창에 보여질 query string
>
<div className='movie'>
<div className='posterContainer'>
{/* 포스터 이미지와 영화 타이틀 보여주는 코드 생략 */}
</div>
</Link>
))}
</div>
)
}
홈 화면에서 query string으로 title 과 poster 데이터를 넘겨주면 해당 페이지에서 useRouter 의 query 메서드로 꺼내 쓸 수 있다.
// /pages/movies/[id].js
import { useRouter } from 'next/router'
import axios from '@/api/axios'
import Image from 'next/image'
export default function Movie() {
const router = useRouter()
const { id, title, poster } = router.query // query 안에 넘겨준 title, poster 데이터가 들어 있다.
return (
<div>
<h4>{title}</h4>
<div className='posterContainer'>
<Image fill className='poster' src={poster} alt={`${title} poster`} />
</div>
</div>
)
}

기본 적으로 useRouter 의 push 메서드로 페이지를 이동하려면,
첫 번째 인자에 이동하려는 페이지의 query string 을 넣는다.
이 때, 첫 번째 인자에 Link 컴포넌트에서와 같이 아래와 같은 객체를 넣고,
{ pathname: '실제 이동 경로', query : {/* 전달하려는 데이터 */ } }
두 번째 인자로 주소창에 보여줄 url query string 을 넣으면 된다.
import { useRouter } from 'next/router'
const router = useRouter()
const handleClick = (id, title, poster) => {
router.push(
{ pathname: `/movies/${id}`, // 실제 이동하려는 페이지의 query string
query: { title, poster } }, // 넘겨 줄 데이터
`/movies/${id}` // 주소창에 보여 줄 url query string
)
}
// /pages/index.js
import Image from 'next/image'
import Link from 'next/link'
import axios from '@/api/axios'
import { useRouter } from 'next/router'
// 서버 사이드 렌더링으로 movies 데이터를 받아옴
export const getServerSideProps = async () => {
const { data } = await axios.get('/popular?language=en-US&page=1')
return { props: { movies: data.results } }
}
export default function Home({ movies = [] }) {
const router = useRouter()
const handleClick = (id, title, poster) => {
router.push(
{
pathname: `/movies/${id}`, // 실제 이동하려는 페이지의 query string
query: { title, poster: `https://image.tmdb.org/t/p/w500/${poster}` }, // 넘겨 줄 데이터
},
`/movies/${id}` // 주소창에 보여 줄 url query string
)
}
return (
<div className='container'>
{movies?.map(movie => (
<div className='movie' key={movie.id}>
<div onClick={() => {
handleClick(movie.id, movie.original_title, movie.poster_path)
}} className='posterContainer'>
{/* 포스터 이미지와 영화 타이틀 보여주는 코드 생략 */}
</div>
))}
</div>
)
}