Front-end/Next.js

[노마드코더] #6 Dynamic Routes & Detail

성중 2022. 2. 24. 14:58

Dynamic Routes

'/movies/all' 이라는 url을 만들고 싶다면?

 

pages 폴더 안에 movies 폴더를 만들고 all.js 파일을 생성

그냥 '/movies' 라는 url을 만들고 싶다면?

 

movies 폴더에 index.js 파일을 생성

* pages 폴더에 movies.js 파일을 생성해도 되지만 하위 url이 있을 경우 이게 더 깔끔

 

'/movies/123' 이런 식으로 url에 변수를 넣고 싶다면?

 

movies 폴더에 [변수명].js 파일을 생성

[pages/movies/[id].js]

import { useRouter } from "next/router";
 
export default function Detail() {
  const router = useRouter();
  console.log(router);
  return <>detail</>;
}

이렇게 작성하고 콘솔에 찍힌 router를 살펴보면..

 

http://localhost:3000/movies/123 로 접속

router의 query가 변수명: "url에 입력한 값" 으로 들어온다 !

 

Detail

Dynamic Routes를 활용해 데이터별로 상세 페이지를 만들어보자

 

[pages/index.js]

import Link from "next/link";
export default function Home(props) {
  return (
...
      {props.results.map((movie) => (
        <Link href={`/movies/${movie.id}`} key={movie.id}>
          <a>
            <div className="movie">
...
            </div>
          </a>
        </Link>
      ))}

map 내부를 Link로 감싸고 href에 map의 id 값을 넣어서 url을 이동할 수 있다

* 원래 Link(a 태그)에 div(flow content)를 넣으면 안되지만 HTML5부터는 가능하다

 

import { useRouter } from "next/router";
 
export default function Home(props) {
  const router = useRouter();
  return (
...
      {props.results.map((movie) => (
        <div
          onClick={() => router.push(`/movies/${movie.id}`)}
          className="movie"
          key={movie.id}
        >
...
        </div>
      ))}

onClick 함수에 router.push를 넣어서 url을 이동할 수도 있다

 

  onClick={() =>
    router.push(
      {
        pathname: `/movies/${movie.id}`,
        query: {
          title: movie.original_title,
          poster: movie.poster_path,
        },
      }
    )
  }

이때, query에 객체 형식으로 데이터를 함께 보낼 수 있다

 

url에 이런 식으로 데이터가 들어오는데

  onClick={() =>
    router.push(
      {
        pathname: `/movies/${movie.id}`,
        query: {
          title: movie.original_title,
          poster: movie.poster_path,
        },
      },
      `/movies/${movie.id}`
    )
  }

이렇게 바로 url을 masking 해줄 수 있다

 

router의 query에는 데이터가 그대로 담겨있다

[pages/movies/[id].js]

import { useRouter } from "next/router";
 
export default function Detail() {
  const router = useRouter();
  return (
    <div>
      <h4>{router.query.title || "Loading..."}</h4>
      <img src={`https:/image.tmdb.org/t/p/w500/${router.query.poster}`} />
    </div>
  );
}

router.query에서 데이터를 받아 사용할 수 있다

 

[pages/index.js]

  <Link
    href={{
      pathname: `/movies/${movie.id}`,
      query: {
        title: movie.original_title,
        poster: movie.poster_path,
      },
    }}
    as={`/movies/${movie.id}`}
  >
    <a>
      <h4>{movie.original_title}</h4>
    </a>
  </Link>

해당 방식은 Link의 href에서도 동일하다 !

 

다만 router.query를 받아오는 방식은 유저가 클릭을 통해 해당 페이지에 들어왔을 때만 유효하다

* 새로고침 하거나 url을 바로 타고 들어오는 경우를 대응하려면 결국 API를 받아와야 하지만, 받아오는 시간동안 router.query를 보여주는 의의가 있다

 

상세 데이터를 API 문서에서 확인하고

 

API Docs

 

developers.themoviedb.org

[next.config.js]

  async rewrites() {
    return [
      {
        source: "/api/movies",
        destination: `https://api.themoviedb.org/3/movie/popular?api_key=${API_KEY}`,
      },
      {
        source: "/api/movies/:id",
        destination: `https://api.themoviedb.org/3/movie/:id?api_key=${API_KEY}`,
      },
    ];
  },

API Key를 포함하기 때문에 Rewrite로 masking 해주자

* source와 destination의 변수명이 같아야 한다

 

잘 불러와진다!

해당 데이터들도 상세 페이지에 바로 fetch하거나 getServerSideProps로 넣어주면 된다 !

 

본 내용은 노마드코더의 'NextJS 시작하기'를 바탕으로 작성되었습니다