> 웹 프론트엔드 > CSS 튜토리얼 > React를 사용하여 Movie Finder 웹사이트 구축하기

React를 사용하여 Movie Finder 웹사이트 구축하기

DDD
풀어 주다: 2024-09-13 12:39:34
원래의
585명이 탐색했습니다.

Building a Movie Finder Website using React

소개

이번 블로그에서는 React와 OMDB API를 사용하여 Movie Finder 웹사이트를 구축하는 과정을 살펴보겠습니다. 이 웹사이트를 통해 사용자는 어벤져스, 스타워즈, 시리즈 등의 카테고리별로 영화를 탐색하고 특정 검색어를 사용하여 영화를 검색할 수 있습니다. 각 영화에는 세부 정보 페이지가 있어 좋아하는 영화에 대해 더 쉽게 탐색할 수 있습니다.

프로젝트 개요

Movie Finder 웹사이트를 통해 사용자는 다음을 수행할 수 있습니다.

  • 어벤져스, 스타워즈 등의 카테고리를 찾아보세요.
  • 키워드로 영화를 검색하세요.
  • 영화 상세 정보(포스터, 장르, 감독, 배우 등)를 확인하세요.
  • 깔끔하고 모던한 디자인으로 웹사이트를 쉽게 탐색하세요.

특징

  • OMDB API를 사용하여 동적으로 데이터를 가져옵니다.
  • 더 나은 사용자 경험을 위한 반응형 디자인
  • 즉시 결과를 제공하는 검색 기능
  • 데이터를 가져오는 동안 표시기를 로드합니다.
  • 별도의 페이지에서 개별 영화의 세부정보를 확인하세요.

사용된 기술

  • React: UI 구성요소 구축을 위한 프런트엔드 라이브러리
  • React Router: 탐색 및 라우팅용.
  • Axios: OMDB API에 대한 HTTP 요청용.
  • OMDB API: 영화 세부정보를 가져옵니다.
  • CSS: 애플리케이션 스타일을 지정합니다.

프로젝트 구조

프로젝트의 디렉토리 구조는 다음과 같습니다.

movie-finder/
├── public/
├── src/
│   ├── components/
│   │   └── Navbar.js
│   │   └── Footer.js
│   ├── pages/
│   │   └── Home.js
│   │   └── Movies.js
│   │   └── Series.js
│   │   └── SearchResults.js
│   │   └── MovieDetail.js
│   └── App.js
│   └── App.css
└── package.json
로그인 후 복사

설치

  1. 저장소 복제:

    git clone https://github.com/abhishekgurjar-in/movie-finder.git
    cd movie-finder
    
    로그인 후 복사
  2. 종속성 설치:

    npm install
    
    로그인 후 복사
  3. OMDB API에서 API 키를 받으세요.

  4. 프로젝트 루트에 .env 파일을 생성하고 API 키를 추가하세요.

    REACT_APP_OMDB_API_KEY=yourapikey
    
    로그인 후 복사
  5. 프로젝트 실행:

    npm start
    
    로그인 후 복사

용법

1. 홈페이지

홈페이지에서는 어벤져스와 스타워즈라는 두 가지 카테고리의 영화를 선보입니다. 사용자가 영화 카드를 클릭하면 영화 상세 페이지로 리디렉션됩니다.

Home.js의 코드 조각:

import React, { useEffect, useState } from "react";
import axios from "axios";
import { useNavigate } from "react-router-dom";
import Movies from "./Movies";
import Series from "./Series";

const Home = () => {
  const [avengersMovies, setAvengersMovies] = useState([]);
  const [starWarsMovies, setStarWarsMovies] = useState([]);
  const [loadingAvengers, setLoadingAvengers] = useState(true);
  const [loadingStarWars, setLoadingStarWars] = useState(true);
  const navigate = useNavigate();

  useEffect(() => {
    fetchMovies("Avengers", setAvengersMovies, setLoadingAvengers);
    fetchMovies("Star Wars", setStarWarsMovies, setLoadingStarWars);
  }, []);

  const fetchMovies = (query, setMovies, setLoading) => {
    axios
      .get(`http://www.omdbapi.com/?s=${query}&apikey=you_api_key`)
      .then((response) => {
        if (response.data.Search) {
          setMovies(response.data.Search);
        } else {
          setMovies([]); // Clear movies if no results
        }
      })
      .catch((error) => {
        console.error(`There was an error fetching the ${query} movies!`, error);
        setMovies([]); // Clear movies if there is an error
      })
      .finally(() => {
        setLoading(false);
      });
  };

  const handleCardClick = (id) => {
    navigate(`/movie/${id}`);
  };

  const renderMovies = (movies, loading) => (
    loading ? (
      <div className="loader"><div className="load"></div></div>
    ) : (
      <div className="cards">
        {movies.length > 0 ? (
          movies.map((movie) => (
            <div key={movie.imdbID} className="card" onClick={() => handleCardClick(movie.imdbID)}>
              <img src={movie.Poster} alt={movie.Title} />
              <h2>{movie.Title}</h2>
            </div>
          ))
        ) : (
          <p>No movies found.</p>
        )}
      </div>
    )
  );

  return (
    <>
      <div className="home">
        <div className="movie-category">
          <h4>Avengers Movies</h4>
          {renderMovies(avengersMovies, loadingAvengers)}
        </div>
        <br />
        <br />
        <div className="movie-category">
          <h4>Star Wars Movies</h4>
          {renderMovies(starWarsMovies, loadingStarWars)}
        </div>
      </div>
      <Movies />
      <Series />
    </>
  );
};

export default Home;

로그인 후 복사

2. 검색 기능

사용자는 웹사이트 상단의 검색창을 사용하여 모든 영화를 검색할 수 있습니다. 사용자의 쿼리를 기반으로 OMDB API에서 검색 결과를 가져옵니다.

SearchResults.js의 코드 조각:

import React, { useEffect, useState } from "react";
import axios from "axios";
import { useParams, useNavigate } from "react-router-dom";

const SearchResults = () => {
  const [movies, setMovies] = useState([]);
  const [loading, setLoading] = useState(false);
  const { query } = useParams();
  const navigate = useNavigate(); // Add this line to use navigate

  useEffect(() => {
    if (query) {
      setLoading(true);  // Set loading to true before starting the fetch
      axios
        .get(`http://www.omdbapi.com/?s=${query}&apikey=your_api_key`)
        .then((response) => {
          if (response.data.Search) {
            setMovies(response.data.Search);
          } else {
            setMovies([]); // Clear movies if no results
          }
        })
        .catch((error) => {
          console.error("There was an error fetching the movie data!", error);
        })
        .finally(() => {
          setLoading(false);  // Set loading to false once fetch is complete
        });
    }
  }, [query]);

  const handleCardClick = (id) => {
    navigate(`/movie/${id}`); // Navigate to movie detail page
  };

  return (
    <div className="search-results">
      <h4>Search Results for "{query}"</h4>
      {loading ? (
        <div className="loader"><div className="load"></div></div>  // Loader
      ) : (
        <div className="cards">
          {movies.length > 0 ? (
            movies.map((movie) => (
              <div key={movie.imdbID} className="card" onClick={() => handleCardClick(movie.imdbID)}>
                <img src={movie.Poster} alt={movie.Title} />
                <h2>{movie.Title}</h2>
              </div>
            ))
          ) : (
            <p>No results found.</p>
          )}
        </div>
      )}
    </div>
  );
};

export default SearchResults;

로그인 후 복사

3. 영화 상세페이지

사용자가 영화를 클릭하면 영화 세부정보 페이지로 리디렉션됩니다. 이 페이지에는 영화 제목, 포스터, 줄거리, 배우 등이 표시됩니다.

MovieDetail.js의 코드 조각:

import React, { useEffect, useState } from 'react';
import axios from 'axios';
import { useParams } from 'react-router-dom';

const MovieDetail = () => {
  const [movie, setMovie] = useState(null);
  const [loading, setLoading] = useState(true);
  const { id } = useParams();

  useEffect(() => {
    axios.get(`http://www.omdbapi.com/?i=${id}&apikey=your_api_key`)
      .then((response) => {
        setMovie(response.data);
      })
      .catch((error) => {
        console.error("There was an error fetching the movie details!", error);
      })
      .finally(() => {
        setLoading(false);
      });
  }, [id]);

  if (loading) return <div className="loader">
    <div className="load"></div>
  </div>;
  if (!movie) return <div className='loader'>No movie data found!</div>;

  return (
    <div className="movie-detail">

<div className="detail-box">
<h1>{movie.Title}</h1>
<p><strong>Year:</strong> {movie.Year}</p>
      <p><strong>Rating:</strong> {movie.imdbRating}</p>
      <p><strong>Genre:</strong> {movie.Genre}</p>
      <p><strong>Director:</strong> {movie.Director}</p>
      <p><strong>Actors:</strong> {movie.Actors}</p>
      <p><strong>Plot:</strong> {movie.Plot}</p>
      <p><strong>Runtime:</strong> {movie.Runtime}</p>
      <p><strong>Language:</strong> {movie.Language}</p>
      <p><strong>Country:</strong> {movie.Country}</p>
      <p><strong>Awards:</strong> {movie.Awards}</p>
</div>
    <div className="img-box">
    <img src={movie.Poster} alt={movie.Title} />
    </div>
    </div>
  );
};

export default MovieDetail;

로그인 후 복사

4. 영화 및 시리즈 페이지

Movies.jsSeries.js 페이지에는 각각 영화와 TV 시리즈가 나열됩니다.

Movies.js의 코드 조각:

import React, { useEffect, useState } from "react";
import axios from "axios";
import { useNavigate } from "react-router-dom";

const Movies = () => {
  const [movies, setMovies] = useState([]);
  const navigate = useNavigate();

  useEffect(() => {
    axios
      .get(`http://www.omdbapi.com/?s=Avengers&type=movie&apikey=${process.env.REACT_APP_OMDB_API_KEY}`)
      .then(response => setMovies(response.data.Search || []))
      .catch(error => console.error(error));
  }, []);

  const handleCardClick = (id) => {
    navigate(`/detail/${id}`);
  };

  return (
    <div className="movies">
      <h2>Movies</h2>
      <div className="cards">
        {movies.map(movie => (
          <div key={movie.imdbID} className="card" onClick={() => handleCardClick(movie.imdbID)}>
            <img src={movie.Poster} alt={movie.Title} />
            <h3>{movie.Title}</h3>
          </div>
        ))}
      </div>
    </div>
  );
};

export default Movies;
로그인 후 복사

Series.js의 코드 조각:

import React, { useEffect, useState } from "react";
import axios from "axios";
import { useNavigate } from "react-router-dom";

const Series = () => {
  const [series, setSeries] = useState([]);
  const navigate = useNavigate();

  useEffect(() => {
    axios
      .get(`http://www.omdbapi.com/?s=Star Wars&type=series&apikey=${process.env.REACT_APP_OMDB_API_KEY}`)
      .then(response => setSeries(response.data.Search || []))
      .catch(error => console.error(error));
  }, []);

  const handleCardClick = (id) => {
    navigate(`/detail/${id}`);
  };

  return (
    <div className="series">
      <h2>TV Series</h2>
      <div className="cards">
        {series.map(show => (
          <div key={show.imdbID} className="card" onClick={() => handleCardClick(show.imdbID)}>
            <img src={show.Poster} alt={show.Title} />
            <h3>{show.Title}</h3>
          </div>
        ))}
      </div>
    </div>
  );
};

export default Series;
로그인 후 복사

5. Navbar 구성 요소

Navbar 구성요소를 사용하면 사용자가 여러 페이지 사이를 탐색하고 검색을 수행할 수 있습니다.

Navbar.js가 업데이트되었습니다.

import React, { useState } from "react";
import { NavLink, Link } from "react-router-dom";

const Navbar = () => {
  const [searchQuery, setSearchQuery] = useState("");

  const handleSearch = (event) => {
    if (event.key === 'Enter' && searchQuery.trim()) {
      document.getElementById('search-link').click();
    }
  };

  return (
    <div className="navbar">
      <div className="logo">
        <h1>Movie Finder</h1>
      </div>

      <div className="page-list">
        <NavLink to="/">
          <h4>Home</h4>
        </NavLink>
        <NavLink to="/movies">
          <h4>Movies</h4>
        </NavLink>
        <NavLink to="/series">
          <h4>TV Series</h4>
        </NavLink>
      </div>
      <div className="search-box">
        <input
          type="text"
          placeholder="Search for movies or series"
          value={searchQuery}
          onChange={(e) => setSearchQuery(e.target.value)}
          onKeyDown={handleSearch}
        />
        <Link to={`/search/${searchQuery}`} id="search-link">
          <button>Search</button>
        </Link>
      </div>
    </div>
  );
};

export default Navbar;
로그인 후 복사

6. 바닥글 구성요소

바닥글 구성요소는 간단한 바닥글 메시지를 제공합니다.

바닥글.js

import React from 'react';

const Footer = () => {
  return (
    <div className='footer'>
      Made with <span>❤️</span> by Abhishek Gurjar
    </div>
  );
};

export default Footer;
로그인 후 복사
*{
  box-sizing: border-box;
}
body{
  font-family: sans-serif;
  margin: 0;
  padding: 0;
}
.navbar {
  padding-inline: 100px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  background-color: red;
}
.search-btn{
  background-color: red;
}
.logo h1{
  font-size: 25px;
  color:black;
  }
.page-list {
  display: flex;
  align-items: center;
  gap: 40px;
}

.page-list a{
  color: white;
  text-decoration: none;
  font-size: 20px;
}
.page-list a:hover{
color: black;
}
.page-list a.active{
  color: black;
}
.search-box{
  box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px;
  background-color:white;
  color: gray;
  width: 250px;
  height: 40px;
  border-radius: 50px;
  overflow: hidden;
}
.search-box input{
  width: 200px;
  height: 40px;
  margin-left: 10px;
  border: none;
  outline: none;

}
.home{
  margin-block: 40px;
  margin-inline: 60px;

}
.home h4{
  font-size: 16px;
}


.movies{
  margin-block: 40px;
  margin-inline: 60px;

}
.movies h4{
  font-size: 16px;
}
.cards{
  display: flex;
flex-wrap: wrap;
  align-items:center ;
  justify-content: space-between;
  gap: 10px;
}
.card{
  width:200px;
  height:360px;
  border-radius: 10px;
  overflow: hidden;
  box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px;
}
.card img{
  width: 200px;
  height: 290px;
  object-fit: cover;
}
.card h2{
  margin: 10px;
  font-size: 16px;
text-align: center;
}

.series{
  margin-block: 40px;
  margin-inline: 60px;
}
.series h4{
  font-size: 16px;
}
.home{
  margin-block: 40px;
  margin-inline: 60px;

}
.search-results{
  margin-block: 40px;
  margin-inline: 60px;
}
.search-results h4{
  font-size: 16px;
}

.loader{
  min-height: 90vh;
  display: flex;
  align-items: center;
  justify-content: center;
}
/* HTML: <div class="loader"></div> */
.load {
  width: 50px;
  padding: 8px;
  aspect-ratio: 1;
  border-radius: 50%;
  background: #ff1900;
  --_m: 
    conic-gradient(#0000 10%,#000),
    linear-gradient(#000 0 0) content-box;
  -webkit-mask: var(--_m);
          mask: var(--_m);
  -webkit-mask-composite: source-out;
          mask-composite: subtract;
  animation: l3 1s infinite linear;
}
@keyframes l3 {to{transform: rotate(1turn)}}


.movie-detail {
  margin-block: 40px;
  margin-inline: 60px;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
}
img-box{
  width: 50%;
}
.movie-detail img {
  border-radius: 10px;
width: 330px;
 height: auto;
 object-fit: cover;
 box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px;
}

.detail-box{
  width: 50%;
}
.movie-detail p {
  font-size: 18px;
  margin: 10px 0;
}

.movie-detail a {
  display: inline-block;
  margin-top: 20px;
  color: #007bff;
  text-decoration: none;
}

.movie-detail a:hover {
  text-decoration: underline;
}


.footer{
  width: 100%;
  background-color: red;
  text-align: center;
  color: white;
  padding: 20px;
}

로그인 후 복사

라이브 데모

여기에서 Movie Finder 웹사이트의 라이브 데모를 확인하실 수 있습니다.

결론

이번 블로그에서는 React, React Router, Axios를 사용하여 Movie Finder 웹사이트를 만드는 방법을 배웠습니다. 이 프로젝트는 공개 API와 상호 작용하고, React에서 상태를 관리하고, 간단하면서도 기능적인 영화 탐색 경험을 만드는 방법을 보여줍니다.

디자인을 자유롭게 맞춤화하고 사용자 리뷰나 영화 평가와 같은 기능을 추가하여 더욱 역동적으로 만들어 보세요!


크레딧

  • OMDB API
  • 반응
  • 리액트 라우터

작가

Abhishek Gurjar는 실용적이고 기능적인 웹 애플리케이션 제작에 열정을 쏟는 헌신적인 웹 개발자입니다. GitHub에서 더 많은 프로젝트를 확인해 보세요.

위 내용은 React를 사용하여 Movie Finder 웹사이트 구축하기의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:dev.to
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿