이전글 - [Next.js] API 호출을 통한 네비게이션 메뉴 생성
#1. 네비게이션 메뉴에 클릭이벤트 작성하기
네비게이션 메뉴로 만들었던 각 영화의 장르를 클릭하면 해당 장르의 영화들을 썸네일과 함께 보여주도록 만들어 봅시다.
먼저 next/router 를 임포트하고 Nav onclick 이벤트에 라우팅을 등록해줍니다.
import { useRouter } from "next/router"
import useSWR from 'swr'
const BASE_URL = 'https://api.themoviedb.org/3/genre/movie/list';
const API_KEY = process.env.API_KEY;
const fetcher = async (url) => {
const res = await fetch(url)
const data = await res.json()
if (res.status !== 200) {
throw new Error(data.message)
}
return data
}
function Nav() {
const router = useRouter();
const { data, error } = useSWR(
() => `${BASE_URL}?api_key=${API_KEY}&language=ko`, fetcher
)
if (error) return <div>{error.message}</div>
if (!data) return <div>Loading...</div>
return (
<nav className="relative">
<div className="flex px-10 sm:px-20 text-2xl whitespace-nowrap
space-x-10 sm:space-x-20">
{data.genres.map((menu, index) => index < 5 && (
<h2 key={menu.id}
onClick={
() => router.push(`/?menu=${menu.id}`, '/')
}
className="last:pr-24 cursor-pointer transition
duration-100 transform hover:scale-125 hover:text-white
active:text-red-500"
>{menu.name}
</h2>
))}
</div>
</nav>
)
}
export default Nav
router.push의 사용법은 다음과 같습니다.
router.push(url, as, options)
url 뒤에 붙는 as 파라미터를 통해 주소표시줄을 변경할 수 있습니다. 생략하게 되면 localhost:3000/?menu=3 이런식으로 표현되지만 예제체럼 '/' 로 옵션을 주면 실제 주소표시줄에서 나타나게 되는 주소는 변함없이 localhost:3000/ 로 보여지게 됩니다.
이제 index.js에서 getServerSideProps를 등록하여 router를 처리해봅시다.
import Head from 'next/head'
import Header from '../components/Header'
import Nav from '../components/Nav'
export default function Home({ contents }) {
return (
<div className=''>
<Head>
<title>Create Next App</title>
<meta name="description" content="Generated by create next app" />
<link rel="icon" href="/favicon.ico" />
</Head>
{/* 헤더 */}
<Header />
{/* 메뉴 */}
<Nav />
{/* 컨텐츠 */}
</div>
)
}
export async function getServerSideProps(context) {
const menu = context.query.menu;
const BASE_URL = 'https://api.themoviedb.org';
const API_KEY = process.env.API_KEY;
const res = await fetch(`${BASE_URL}/3/discover/movie?api_key=${API_KEY}&language=kr&with_genres=${menu}`)
const data = await res.json()
return {
props: {
contents: data.results
},
}
}
index페이지가 렌더링 될 때마다 getServerSideProps를 통해 API request를 호출합니다.
사용할 API는 themoviedb API에서 특정 장르의 영화목록을 가져오는
https://api.themoviedb.org/3/discover/movie?api_key=${API_KEY}&language=kr&with_genres=${menu} 를 사용합니다.
장르 메뉴를 클릭하게 되면, localhost:3000/?menu=123 로 라우팅이 되는데, 이를 getServerSideProps(context) 에서
context.query.menu 로 123 값을 가져 올 수 있습니다. 저 menu id는 장르의 id이기 때문에 해당 API에 파라미터로 넣어서 호출하게 되면 각 장르에 맞는 영화 목록을 얻을 수 있습니다.
영화목록 API를 호출한 결과에는 각 영화의 제목, 릴리즈 일자, 포스터 이미지 등등의 영화정보가 들어 있습니다.
이를 사용해서 영화 포스터 목록과 영화정보를 보여주도록 해봅시다.
#2. 영화 이미지 가져오기
API에서 backdrop_path(배경), poster_path(포스터) 를 가져 왔고 이를 https://image.tmdb.org/t/p/original/ 뒤에 붙여서 호출하게 되면 해당 이미지를 얻을 수 있습니다.
components/Contents.js 파일을 만들고 아래와 같이 작성합니다.
import Image from "next/image"
function Contents({ contents }) {
const BASE_URL = "https://image.tmdb.org/t/p/original/";
return (
<div>
This is contents
{contents.map(result => (
<Image
layout="responsive"
src={
`${BASE_URL}${result.backdrop_path || result.poster_path}`
}
height={360}
width={640}
/>
))}
</div>
)
}
export default Contents
또, 외부 이미지 최적화를 위해 next.config.js 파일에도 다음과 같이 이미지 호출을 위한 외부 도메인 주소를 작성합니다.
// next.config.js
module.exports = {
env: {
API_KEY: `7cxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`
},
images: {
domains: ["image.tmdb.org"]
}
};
이제 index.js 에서 작성한 Contents 파일을 임포트 해줍니다. getServerSideProps에서 return 된 영화목록정보를 contents에 담아 contents에 넘겨줍니다.
export default function Home({ contents }) {
return (
<div className=''>
<Head>
<title>Create Next App</title>
<meta name="description" content="Generated by create next app" />
<link rel="icon" href="/favicon.ico" />
</Head>
{/* 헤더 */}
<Header />
{/* 메뉴 */}
<Nav />
{/* 컨텐츠 */}
<Contents contents={contents}/>
</div>
)
}
자 이제 서버를 실행해서 중간 결과를 확인해 봅시다.
#3. 카드 썸네일 만들기
영화 이미지와 함께 영화의 정보를 카드 썸네일 형식으로 배열해서 UI를 변경해봅시다.
components/Thumnail.js 파일을 만들고 Contents에서 호출했던 이미지 정보를 Thumnail파일로 옮기고 영화의 제목을 함께 보여주고, 썸네일에 마우스를 올리면 개봉일, 좋아요 수 등의 정보를 함께 보여줍시다.
import Thumbnail from "./Thumbnail"
function Contents({ contents }) {
return (
<div className="px-5 my-10 sm:grid md:grid-cols-2 xl:grid-cols-3
3xl:flex flex-wrap justify-center">
{contents.map(content => (
<Thumbnail key={content.id} content={content} />
))}
</div>
)
}
export default Contents
해상도가 변경되면 한번에 보여주는 카드의 숫자를 유동적으로 변경하기 위해, sm, md, xl 등의 옵션도 함께 지정합니다.
import { ThumbUpIcon } from "@heroicons/react/outline";
import Image from "next/image"
function Thumbnail({ content }) {
const BASE_URL = "https://image.tmdb.org/t/p/original/";
return (
<div className="p-2 group cursor-pointer transition duration-200
ease-in transform sm:hover:scale-105 hover:z-50">
<Image
layout="responsive"
src={
`${BASE_URL}${content.backdrop_path || content.poster_path}`
}
height={360}
width={640}
/>
<div className="p-2">
<p className="truncate max-w-md">{content.overview}</p>
<h2 className="mt-1 text-2xl text-white transition-all
duration-100 ease-in-out group-hover:font-bold">
{content.title || content.original_name}
</h2>
<p className="flex items-center opacity-0 group-hover:opacity-100">
{content.media_type && `${content.media_type} ㆍ`}{" "}
{content.release_date || content.first_air_date}ㆍ{" "}
<ThumbUpIcon className="h-5 mx-2" /> {content.vote_count}
</p>
</div>
</div>
)
}
export default Thumbnail
최종적으로 만들어진 사이트의 모습입니다.
메뉴 클릭시 새로운 목록을 보여주며, 각 썸네일에 마우스를 올리면 가벼운 효과와 함께 영화의 상세 정보를 보여주고, 해상도에 따라 카드배열의 숫자로 플렉서블하게 변경되는 사이트가 완성되었습니다.
fin.
'Frontend > Next.js' 카테고리의 다른 글
[Next.js] API 호출을 통한 네비게이션 메뉴 생성 (0) | 2021.05.17 |
---|---|
[Next.js] 페이지 상단 레이아웃 생성 (2) | 2021.05.01 |
[Next.js] Next.js 시작하기 (0) | 2021.04.07 |
댓글