[Next.js] url의 query string으로 데이터 넘기기

iberis2·2023년 8월 6일

NextJS

목록 보기
8/10
post-thumbnail

Query String으로 데이터 넘기기

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 으로 데이터를 넘겨줄 수 있다.

import Link from 'next/link'

<Link 
	href = {{ 
        pathname: '이동하려는 주소', 
        query: { /* 넘기려는 데이터를 객체로 작성 */ },
   }}
   as = '유저에게 보여줄 주소'
> 페이지 이동 버튼 </Link>

Link 컴포넌트의 props 로 hrefas 속성을 넣는다.

  • href 에는 pathname 과, query 프로퍼티가 있다.
    • pathname : 이동하려는 주소
    • query : 전달하려는 데이터를 key, value 로 작성한다. useRouter의 query 메서드로 꺼내 쓸 수 있다.
  • as 에는 화면에 보여줄 url 의 query string 을 작성한다.
    • as 속성을 지정해주지 않는다면 url 에 모든 query 가 보이게 된다.
      예를 들어, 아래와 같이 지정되어 있을 때 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으로 titleposter 데이터를 넘겨주면 해당 페이지에서 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>
  )
}

2. useRouter의 .push() 메서드

기본 적으로 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>
  )
}

참고 : 🔗 노마드코더 - Next JS 시작하기

profile
자동화와 기록으로 더 효율적으로 일하는 으른 개발자가 되려고 합니다.

0개의 댓글