Chapter 04

Rowコンポーネントの作成

こんな感じのものを作っていきます。
_2021-01-14_0.55.38.png

必要な機能

・カテゴリー毎に映画の画像を取ってくる
・Top ratedの画像は大きめにする
・列毎に横スライドができるようにする

APIの準備ができたのでコンポーネントを作っていきます。
まずは映画のAPIが取得出来る事を確認してきます。

映画のAPIを取得できるか確認

Row.tsxを作っていきます。
propsとしてtitleとしてカテゴリー名を、fetchUrlとしてそのURLを貰って映画を1列で表示するコンポーネントです。
カテゴリーによっては画像サイズを変更sたいので、、オプショナルでisLargeRowも持っています。
まずはfetchUrlから貰ったデータで映画の情報が正しく受け取れているかを確認します。

Row.tsx


type Props = {
  title: string;
  fetchUrl: string;
  isLargeRow?: boolean;
};

type Movie = {
  id: string;
  name: string;
  title: string;
  original_name: string;
  poster_path: string;
  backdrop_path: string;
};


export const Row = ({ title, fetchUrl }: Props) => {
  const [movies, setMovies] = useState<Movie[]>([]);

  useEffect(() => {
    async function fetchData() {
      const request = await axios.get(fetchUrl);
      setMovies(request.data.results);
      return request;
    }
    fetchData();
  }, [fetchUrl]);

  console.log(movies);

  return(
      <div className="Row" /> 
  );
};

映画のデータはstateで管理します。
useStateにて[]空配列を初期値にして、データが取れ次第更新していきます。

映画のAPIデータは非同期処理にて扱っています。
普通の同期通信だと上から順に処理が終わり次第、次の処理が始まります。
しかし外部から映画の画像取得をいちいち順番にやっていたら、ページ自体の表示がとてつもなく遅くなってしまいます。

ですので、ここではページの表示をいち早く行って、非同期処理を使って後から処理が終わった順でAPIデータを入れていく形をとっています。
非同期処理についてよく分からない方は、こちらの動画が参考になります

https://youtu.be/Vhnz1V-v1cU

今回だとまず、useEffectを使って、非同期処理の発火をfetchUrlが変わる度に設定しています。
useEffectの中では取ってきたデータのstateの更新をしています。

hooksを使った外部APIの取得方法は下記に分かりやすくまとまっています。
React Hooks で外部APIの情報を表示したいときにはどうすればよいのか?

App.tsx側でRowコンポーネントを設置し、必要なtitleとfetchUrlをいれてあげましょう。


<div className="App">
    <Row
      title="NETFLIX ORIGUINALS"
      fetchUrl={requests.feachNetflixOriginals}
      isLargeRow
    />
    <Row title="Top Rated" fetchUrl={requests.feactTopRated} />
    <Row title="Action Movies" fetchUrl={requests.feactActionMovies} />
    <Row title="Comedy Movies" fetchUrl={requests.feactComedyMovies} />
    <Row title="Horror Movies" fetchUrl={requests.feactHorrorMovies} />
    <Row title="Romance Movies" fetchUrl={requests.feactRomanceMovies} />
    <Row title="DOcumentaries" fetchUrl={requests.feactDocumentMovies} />
</div>

console.log(movies);
に対して以下の画像のようなデータが取れていれば、APIは正しく取得できています。

2.png

DOM部分の表示、スタイリング

映画のデータが取れていることが分かったので、DOM部分を作ってscssでスタイリングしていきます。

Rowのreturn部分



 return (
    <div className="Row">
      <h2>{title}</h2>
      <div className="Row-posters">
        {/* ポスターコンテンツ */}
        {movies.map((movie, i) => (
          <img
            key={movie.id}
            className={`Row-poster ${isLargeRow && "Row-poster-large"}`}
            src={`${base_url}${
              isLargeRow ? movie.poster_path : movie.backdrop_path
            }`}
            alt={movie.name}
          />
        ))}
      </div>
    </div>
  );


classNameにてクラス名を振りつつ、映画のポスター画像を表示しています。
mapを用いてmivies配列を1つずつ並べています。

またpropsでisLargeRowを貰った場合は、classNameとsrcが少し変更します。
ここで論理演算式や条件演算子気を使っています。

俺の論理演算子、条件演算子

Row.scss


.Row {
  margin-left: 20px;
  color: #fff;

  &-posters {
    display: flex;
    overflow-y: hidden;
    overflow-x: scroll;
    padding: 20px;

    &::-webkit-scrollbar {
      display: none;
    }
  }

  &-poster {
    object-fit: contain;
    width: 100%;
    max-height: 100px;
    margin: 10px;
    transition: transform 450ms;

    &-large {
      max-height: 250px;

      &:hover {
        transform: scale(1.09);
      }
    }

    &:hover {
      transform: scale(1.08);
    }
  }
}


bject-fit:contain;を使うと、widthかheightの片方のみにpxを入れた場合に、
アスペクト比を崩さないようにもう一方の値を設定してくれます。
画像などの拡大縮小には便利です。

overflow-y:hidden;overflow-x:scroll;はy軸なしでx軸方向にスクロールできるように。
3.png
ここまででTopRatedは大きめ、その他は普通サイズに使い分けられた映画一覧が取得されました。