View on GitHub

映画リストコンポーネントの作成

Home

映画リストコンポーネントの作成

画像ファイルの準備

  1. 下記ファイルをダウンロードする。
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の内容が表示されています。

参考

  1. 手島拓也,吉田健人,高林佳稀,『TypeScriptとReact/Next.jsでつくる 実践Webアプリケーション開発』,技術評論社,2022.
    • 6.2.3 アプリケーションで使用されるデータの型