Movie API - Movielist

sang one leee·2023년 5월 28일
0

React 이모저모

목록 보기
6/8

핵심 기능인 MovieList, 영화 데이터를 불러오고 리스트로 나열한다.

영화 제목을 받는 input, 영화 평점 option
평점은 대체로 낮아서 주로 선택하지 않고 검색하긴 한다.


영화 검색 후 list 가 나열되고 옆으로 스크롤 가능하게 만들었다.

import axios from "axios";
import { useEffect } from "react";
import { useState } from "react";
import "./list.css";
import { Navigate, useNavigate, useSearchParams } from "react-router-dom";
import { API_KEY, IMG_BASE_URL } from "../constant";

const MoviePage = () => {
  const [keyword, setKeyword] = useState("");
  const [movieList, setMovieList] = useState([]);
  const [rating, setRating] = useState(0);
  const navigate = useNavigate();

  useEffect(() => {
    console.log("movieList", movieList);
  }, [movieList]);


  const handleSubmitKeyword = async (e) => {
    e.preventDefault();
    if (keyword.trim() === "") {
      alert("검색어를 입력해주세요.");
      return;
    }


    const { data } = await axios
      .get(`https://api.themoviedb.org/3/search/movie?query=${keyword}`, {
        headers: {
          Authorization: API_KEY,
        },
      })
      .catch((e) => {
        console.log(e);
      });
    setMovieList(data.results);
  };

  const handleChangeKeyword = (e) => {
    setKeyword(e.target.value);
  };

  const handleChangeRating = (e) => {
    setRating(e.target.value);
  };

  return (
    <div className="page_container">
      <h1 className="page_title">Search the Movie</h1>
      <div className="list_search_container">
        <form
          onSubmit={handleSubmitKeyword}
          className="search_option_container"
        >
          <input
            value={keyword}
            onChange={handleChangeKeyword}
            placeholder="영화 제목"
            className="search_keyword"
          />
          <select
            value={rating}
            onChange={handleChangeRating}
            className="search_rating"
          >
            <option value={0}>선택안함</option>
            <option value={7.0}>7.0 이상</option>
            <option value={7.5}>7.5 이상</option>
            <option value={8.0}>8.0 이상</option>
            <option value={8.5}>8.5 이상</option>
            <option value={9.0}>9.0 이상</option>
          </select>
          <button type="submit" className="search_submit">
            검색
          </button>
        </form>
      </div>

      <div className="movie_list_container">
        <ul className="movie_list">
          {movieList.map(
            ({ id, title, poster_path, release_date, vote_average }, index) => {
              if (rating <= vote_average)
                return (
                  <li key={`${id}_${index}`} className="movie_list_item">
                    <div className="contents_container">
                      <div className="list_title">{title}</div>
                      {poster_path ? (
                        <img
                          className="list_img"
                          src={`${IMG_BASE_URL}${poster_path}`}
                          onClick={() => {
                            navigate(`/detail/${id}`);
                          }}
                        />
                      ) : (
                        <div className="list_no_img">이미지 없음</div>
                      )}
                      <div className="list_release_date">
                        출시일 : {release_date}
                      </div>
                      <div className="list_rating">평점 : {vote_average}</div>
                    </div>
                  </li>
                );
            }
          )}
        </ul>
      </div>
    </div>
  );
};

export default MoviePage;

useStateuseEffect을 사용했다.

먼저, useState

const [state, setState] = useState(initialState);

상태 유지 값과 그 값을 갱신하는 함수를 반환합니다.
최초로 렌더링을 하는 동안, 반환된 state(state)는 첫 번째 전달된 인자(initialState)의 값과 같습니다. setState 함수는 state를 갱신할 때 사용합니다. 새 state 값을 받아 컴포넌트 리렌더링을 큐에 등록합니다. - react 공식문서

간단하게 말해서 상태를 저장할 수 있는거다. list를 나열할때 우리가 상태를 저장해야 하는 것은 keyword 와 평점, 그리고 받아온 데이터를 저장하는 list가 필요하다. API 마다 조건이 다르겠지만 이 곳에서는 기본 링크 뒤에 keyword를 query로 사용한다. 따라서 input에서 받아온 keyword를 State에 저장하고 평점은 선택된 option 값에 따라서 Rendering에서 조건문으로 return 해준다. 처음에 불러온 데이터의 형태를 확인하면 객체 형태인걸 알 수 있다. 데이터를 확인하고 싶다면 네트워크 > Fetch/XHR > 미리보기에서 확인 가능하지만 바로 콘솔에 띄우고 싶다면 useEffect를 사용하는 것이 편하다. 받아온 데이터의 형태가 많고 객체형태로 있었기에 list를 화면에 띄우려면 배열로 만들어 .map을 돌려야 했다. 따라서 movieList에 초기값은 []이다.

*useEffect
ffect는 종종 컴포넌트가 화면에서 제거될 때 정리해야 하는 리소스를 만듭니다. 가령 구독이나 타이머 ID와 같은 것입니다. 이것을 수행하기 위해서 useEffect로 전달된 함수는 정리(clean-up) 함수를 반환할 수 있습니다. 예를 들어 구독을 생성하는 경우는 아래와 같습니다.

useEffect(() => {
  const subscription = props.source.subscribe();
  return () => {
    // Clean up the subscription
    subscription.unsubscribe();
  };
});

정리 함수는 메모리 누수 방지를 위해 UI에서 컴포넌트를 제거하기 전에 수행됩니다. 더불어, 컴포넌트가 (그냥 일반적으로 수행하는 것처럼) 여러 번 렌더링 된다면 다음 effect가 수행되기 전에 이전 effect는 정리됩니다. - React 공식문서

CSS

.page_container {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
}

.page_title {
  display: flex;
  flex-direction: column;
  align-items: center;
  font-size: 50px;
  font-weight: 100;
}

.list_search_container {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.search_keyword {
  border-radius: 5px;
  border: 1px solid black;
  width: 140px;
  line-height: 20px;
}

.search_rating {
  margin-left: 7px;
  margin-right: 7px;
  border: 1px solid black;
  border-radius: 5px;
  line-height: 20px;
}

.movie_list_container {
  display: flex;
  flex-direction: column;
}

.movie_list {
  overflow-x: scroll;
  white-space: nowrap;
  display: flex;
  flex-direction: row;
  height: 100%;
  width: 100%;
  margin-top: 20px;
}

.movie_list_item {
  width: fit-content;
  height: fit-content;
  display: flex;
  flex-direction: column;
}

.contents_container {
  width: 300px;
  height: 400px;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.list_img {
  width: 100%;
  height: 80%;
  object-fit: contain;
  border-radius: 8px;
  overflow: hidden;
  padding: 6px;
}
profile
코린이 화이팅

0개의 댓글