映画リストコンポーネントの作成
画像ファイルの準備
- 下記ファイルをダウンロードする。
- recsyslab / recsys_full / src / frontend / public / img /
dummy_poster.png
- recsyslab / recsys_full / src / frontend / public / img /
frontend$ mkdir -p public/img/
frontend$ mv ~/Downloads/dummy_poster.png public/img/
データ型
frontend/src/types/data.d.ts
...(略)...
// 映画
export type Movie = {
id: number;
title: string;
year: number;
genres: string[];
imdb_id: number;
tmdb_id: number;
};
コンポーネント
映画カードコンポーネント
frontend/src/app/components/movie/MovieCard.tsx
import { Movie } from '@/types/data';
import Image from 'next/image';
import Link from 'next/link';
import React from 'react';
type Props = {
movie: Movie;
};
const MovieCard = (props: Props) => {
const img_url = '/img/dummy_poster.png';
return (
<>
<article className="h-72 w-32 shadow" key={props.movie.id}>
<Link href={`/movies/${props.movie.id}`} className="hover:opacity-75">
<Image src={img_url} alt="" width={120} height={180} priority={true} />
</Link>
<div className="mx-1">
<div className="line-clamp-2 font-semibold text-gray-800">{props.movie.title}</div>
<div className="flex">
<div className="my-1 rounded bg-gray-200 px-1 py-0.5 text-sm text-gray-800">
{props.movie.year}
</div>
</div>
</div>
</article>
</>
);
};
export default MovieCard;
映画リストコンポーネント
frontend/src/app/components/movie/MovieList.tsx
'use client';
import { Movie } from '@/types/data';
import React, { useEffect, useState } from 'react';
import MovieCard from './MovieCard';
type Props = {
phrase: string;
movies: Movie[];
perPage: number;
};
const MovieList = (props: Props) => {
const [movies, setMovies] = useState<Movie[]>(props.movies);
const [currentMovies, setCurrentMovies] = useState<Movie[]>();
useEffect(() => {
const start = 0;
const end = start + props.perPage;
const currentMovies_ = movies.slice(start, end);
setCurrentMovies(currentMovies_);
}, [movies]);
return (
<>
<div className="text-xl font-bold text-gray-800">{props.phrase}</div>
<div className="mx-4 my-4 flex justify-between">
{currentMovies?.map((movie) => <MovieCard movie={movie} key={movie.id} />)}
</div>
</>
);
};
export default MovieList;
ページ
インデックスページ
frontend/src/app/page.tsx
import { SessionProvider } from 'next-auth/react';
import React from 'react';
import HelloAccount from './components/HelloAccount';
import connectUser from '@/services/users/connectUser';
import MovieList from './components/movie/MovieList'; // <- 追加
const PER_PAGE = 5; // <- 追加
const Index = async () => {
await connectUser();
// ↓追加
const { movies } = {
movies: [
{
id: 1,
title: 'Toy Story',
year: 1995,
genres: ['Adventure', 'Animation', 'Children', 'Comedy', 'Fantasy'],
imdb_id: 114709,
tmdb_id: 862,
},
{
id: 2,
title: 'Jumanji',
year: 1995,
genres: ['Adventure', 'Children', 'Fantasy'],
imdb_id: 113497,
tmdb_id: 8844,
},
{
id: 3,
title: 'Grumpier Old Men',
year: 1995,
genres: ['Comedy', 'Romance'],
imdb_id: 113228,
tmdb_id: 15602,
},
{
id: 4,
title: 'Waiting to Exhale',
year: 1995,
genres: ['Comedy', 'Drama', 'Romance'],
imdb_id: 114885,
tmdb_id: 31357,
},
{
id: 5,
title: 'Father of the Bride Part II',
year: 1995,
genres: ['Comedy'],
imdb_id: 113041,
tmdb_id: 11862,
},
{
id: 6,
title: 'Heat',
year: 1995,
genres: ['Action', 'Crime', 'Thriller'],
imdb_id: 113277,
tmdb_id: 949,
},
{
id: 7,
title: 'Sabrina',
year: 1995,
genres: ['Comedy', 'Romance'],
imdb_id: 114319,
tmdb_id: 11860,
},
{
id: 8,
title: 'Tom and Huck',
year: 1995,
genres: ['Adventure', 'Children'],
imdb_id: 112302,
tmdb_id: 45325,
},
],
};
console.log(movies);
// ↑追加
return (
<>
<section>
<SessionProvider>
<HelloAccount />
</SessionProvider>
<MovieList phrase="本日のおすすめ" movies={movies} perPage={PER_PAGE} /> {/* <- 追加 */}
</section>
</>
);
};
export default Index;
ブラウザで下記URLにアクセスすると、映画リストが表示されます。また、フロントエンドサーバ側のコンソール(yarn dev
を実行した端末)にmovies
の内容が表示されています。
参考
- 手島拓也,吉田健人,高林佳稀,『TypeScriptとReact/Next.jsでつくる 実践Webアプリケーション開発』,技術評論社,2022.
- 6.2.3 アプリケーションで使用されるデータの型