이번 블로그에서는 React와 OMDB API를 사용하여 Movie Finder 웹사이트를 구축하는 과정을 살펴보겠습니다. 이 웹사이트를 통해 사용자는 어벤져스, 스타워즈, 시리즈 등의 카테고리별로 영화를 탐색하고 특정 검색어를 사용하여 영화를 검색할 수 있습니다. 각 영화에는 세부 정보 페이지가 있어 좋아하는 영화에 대해 더 쉽게 탐색할 수 있습니다.
Movie Finder 웹사이트를 통해 사용자는 다음을 수행할 수 있습니다.
프로젝트의 디렉토리 구조는 다음과 같습니다.
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
저장소 복제:
git clone https://github.com/abhishekgurjar-in/movie-finder.git cd movie-finder
종속성 설치:
npm install
OMDB API에서 API 키를 받으세요.
프로젝트 루트에 .env 파일을 생성하고 API 키를 추가하세요.
REACT_APP_OMDB_API_KEY=yourapikey
프로젝트 실행:
npm start
홈페이지에서는 어벤져스와 스타워즈라는 두 가지 카테고리의 영화를 선보입니다. 사용자가 영화 카드를 클릭하면 영화 상세 페이지로 리디렉션됩니다.
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 ? ( 391706c98a6bb525cf4d3f804c3e9b3baac6cad6c09b9658b5b35f3523d88d1116b28748ea4df4d9c2150843fecfba6816b28748ea4df4d9c2150843fecfba68 ) : ( 708b1d1285701e251e9fa1f2193b7d63 {movies.length > 0 ? ( movies.map((movie) => ( 12728e1adecf83573e180dc578e2e2c2 handleCardClick(movie.imdbID)}> 53f77bfc03dd61d765abffefdb992f4f c1a436a314ed609750bd7c7d319db4da{movie.Title}2e9b454fa8428549ca2e64dfac4625cd 16b28748ea4df4d9c2150843fecfba68 )) ) : ( e388a4556c0f65e1904146cc1a846beeNo movies found.94b3e26ee717c64999d7867364b1b4a3 )} 16b28748ea4df4d9c2150843fecfba68 ) ); return ( a8093152e673feb7aba1828c43532094 5e12fe6a884c5486b6a8efaa94283304 9b0bcc9b98322501402178b0f3be9a1e 3f7b3decd2dcafb07b84d2d3985d9f40Avengers Movies0f6dfd1e3624ce5465eb402e300e01ae {renderMovies(avengersMovies, loadingAvengers)} 16b28748ea4df4d9c2150843fecfba68 df250b2156c434f3390392d09b1c9563 df250b2156c434f3390392d09b1c9563 9b0bcc9b98322501402178b0f3be9a1e 3f7b3decd2dcafb07b84d2d3985d9f40Star Wars Movies0f6dfd1e3624ce5465eb402e300e01ae {renderMovies(starWarsMovies, loadingStarWars)} 16b28748ea4df4d9c2150843fecfba68 16b28748ea4df4d9c2150843fecfba68 52f3849cf2c3f31cc82a4e8b32ced1d3 ecdc054e702196f465a773413a599e82 5f557f62ae7ac7a14e0b1cb564790dfc ); }; export default Home;
사용자는 웹사이트 상단의 검색창을 사용하여 모든 영화를 검색할 수 있습니다. 사용자의 쿼리를 기반으로 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 ( bf6ea6bca350fbd36c62942eeadc3f36 3f7b3decd2dcafb07b84d2d3985d9f40Search Results for "{query}"0f6dfd1e3624ce5465eb402e300e01ae {loading ? ( 391706c98a6bb525cf4d3f804c3e9b3baac6cad6c09b9658b5b35f3523d88d1116b28748ea4df4d9c2150843fecfba6816b28748ea4df4d9c2150843fecfba68 // Loader ) : ( 708b1d1285701e251e9fa1f2193b7d63 {movies.length > 0 ? ( movies.map((movie) => ( 12728e1adecf83573e180dc578e2e2c2 handleCardClick(movie.imdbID)}> 53f77bfc03dd61d765abffefdb992f4f c1a436a314ed609750bd7c7d319db4da{movie.Title}2e9b454fa8428549ca2e64dfac4625cd 16b28748ea4df4d9c2150843fecfba68 )) ) : ( e388a4556c0f65e1904146cc1a846beeNo results found.94b3e26ee717c64999d7867364b1b4a3 )} 16b28748ea4df4d9c2150843fecfba68 )} 16b28748ea4df4d9c2150843fecfba68 ); }; export default SearchResults;
사용자가 영화를 클릭하면 영화 세부정보 페이지로 리디렉션됩니다. 이 페이지에는 영화 제목, 포스터, 줄거리, 배우 등이 표시됩니다.
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 391706c98a6bb525cf4d3f804c3e9b3b aac6cad6c09b9658b5b35f3523d88d1116b28748ea4df4d9c2150843fecfba68 16b28748ea4df4d9c2150843fecfba68; if (!movie) return bc3517ed53a2992e46268da16e3f760bNo movie data found!16b28748ea4df4d9c2150843fecfba68; return ( 5d4fb5b3e2c1bf52ca40540d9f64ecf6 7d32ff64584c41174c506c75fd1c43f8 4a249f0d628e2318394fd9b75b4636b1{movie.Title}473f0a7621bec819994bb5020d29372a e388a4556c0f65e1904146cc1a846bee8e99a69fbe029cd4e2b854e244eab143Year:128dba7a3a77be0113eb0bea6ea0a5d0 {movie.Year}94b3e26ee717c64999d7867364b1b4a3 e388a4556c0f65e1904146cc1a846bee8e99a69fbe029cd4e2b854e244eab143Rating:128dba7a3a77be0113eb0bea6ea0a5d0 {movie.imdbRating}94b3e26ee717c64999d7867364b1b4a3 e388a4556c0f65e1904146cc1a846bee8e99a69fbe029cd4e2b854e244eab143Genre:128dba7a3a77be0113eb0bea6ea0a5d0 {movie.Genre}94b3e26ee717c64999d7867364b1b4a3 e388a4556c0f65e1904146cc1a846bee8e99a69fbe029cd4e2b854e244eab143Director:128dba7a3a77be0113eb0bea6ea0a5d0 {movie.Director}94b3e26ee717c64999d7867364b1b4a3 e388a4556c0f65e1904146cc1a846bee8e99a69fbe029cd4e2b854e244eab143Actors:128dba7a3a77be0113eb0bea6ea0a5d0 {movie.Actors}94b3e26ee717c64999d7867364b1b4a3 e388a4556c0f65e1904146cc1a846bee8e99a69fbe029cd4e2b854e244eab143Plot:128dba7a3a77be0113eb0bea6ea0a5d0 {movie.Plot}94b3e26ee717c64999d7867364b1b4a3 e388a4556c0f65e1904146cc1a846bee8e99a69fbe029cd4e2b854e244eab143Runtime:128dba7a3a77be0113eb0bea6ea0a5d0 {movie.Runtime}94b3e26ee717c64999d7867364b1b4a3 e388a4556c0f65e1904146cc1a846bee8e99a69fbe029cd4e2b854e244eab143Language:128dba7a3a77be0113eb0bea6ea0a5d0 {movie.Language}94b3e26ee717c64999d7867364b1b4a3 e388a4556c0f65e1904146cc1a846bee8e99a69fbe029cd4e2b854e244eab143Country:128dba7a3a77be0113eb0bea6ea0a5d0 {movie.Country}94b3e26ee717c64999d7867364b1b4a3 e388a4556c0f65e1904146cc1a846bee8e99a69fbe029cd4e2b854e244eab143Awards:128dba7a3a77be0113eb0bea6ea0a5d0 {movie.Awards}94b3e26ee717c64999d7867364b1b4a3 16b28748ea4df4d9c2150843fecfba68 bcf6b949990d2b26854fc1a0235e7896 53f77bfc03dd61d765abffefdb992f4f 16b28748ea4df4d9c2150843fecfba68 16b28748ea4df4d9c2150843fecfba68 ); }; export default MovieDetail;
Movies.js 및 Series.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 ( d40b792c730e4d11d0eca74a10366575 c1a436a314ed609750bd7c7d319db4daMovies2e9b454fa8428549ca2e64dfac4625cd 708b1d1285701e251e9fa1f2193b7d63 {movies.map(movie => ( 12728e1adecf83573e180dc578e2e2c2 handleCardClick(movie.imdbID)}> 53f77bfc03dd61d765abffefdb992f4f 684271ed9684bde649abda8831d4d355{movie.Title}39528cedfa926ea0c01e69ef5b2ea9b0 16b28748ea4df4d9c2150843fecfba68 ))} 16b28748ea4df4d9c2150843fecfba68 16b28748ea4df4d9c2150843fecfba68 ); }; 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 ( 31838116f0659c8e0fe2d7d1854d0e7a c1a436a314ed609750bd7c7d319db4daTV Series2e9b454fa8428549ca2e64dfac4625cd 708b1d1285701e251e9fa1f2193b7d63 {series.map(show => ( 01c7d619b10fabc0744128b826b29a0f handleCardClick(show.imdbID)}> a9c0cac5f8f3bc0104ebd6d33bb9bd98 684271ed9684bde649abda8831d4d355{show.Title}39528cedfa926ea0c01e69ef5b2ea9b0 16b28748ea4df4d9c2150843fecfba68 ))} 16b28748ea4df4d9c2150843fecfba68 16b28748ea4df4d9c2150843fecfba68 ); }; export default Series;
Navbar 구성요소를 사용하면 사용자가 여러 페이지 사이를 탐색하고 검색을 수행할 수 있습니다.
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 ( 6de5cdabed8c37e65ec07ad5a9b8f878 788a37ae874cfc6a3ed79faf72b77879 4a249f0d628e2318394fd9b75b4636b1Movie Finder473f0a7621bec819994bb5020d29372a 16b28748ea4df4d9c2150843fecfba68 48f38cae923f5e26c602cafad0cbf526 7a33e57c3b200f2f5ecc2e455318e8cf 3f7b3decd2dcafb07b84d2d3985d9f40Home0f6dfd1e3624ce5465eb402e300e01ae adb9ac3aead1d3fba02ca688b8636d1b 652dfcca303e1ed15c65622e15127ba2 3f7b3decd2dcafb07b84d2d3985d9f40Movies0f6dfd1e3624ce5465eb402e300e01ae adb9ac3aead1d3fba02ca688b8636d1b d63227fa461236d17a6381d446ab43a0 3f7b3decd2dcafb07b84d2d3985d9f40TV Series0f6dfd1e3624ce5465eb402e300e01ae adb9ac3aead1d3fba02ca688b8636d1b 16b28748ea4df4d9c2150843fecfba68 a349cf54cf26717db21be5f2029cbdd5 a09ba7022bc6a6807a1896f2a858385a setSearchQuery(e.target.value)} onKeyDown={handleSearch} /> e4f7f070cfb179e9f270abf5ddd9c301 bb9345e55eb71822850ff156dfde57c8Search65281c5ac262bf6d81768915a4a77ac0 06f735b502bd5273dad825215f7c405b 16b28748ea4df4d9c2150843fecfba68 16b28748ea4df4d9c2150843fecfba68 ); }; export default Navbar;
바닥글 구성요소는 간단한 바닥글 메시지를 제공합니다.
import React from 'react'; const Footer = () => { return ( c36ce888baa3a5bd9bc4a4919fc19de1 Made with 45a2772a6b6107b401db3c9b82c049c2❤️54bdf357c58b8a65c66d7c19c8e4d114 by Abhishek Gurjar 16b28748ea4df4d9c2150843fecfba68 ); }; 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: 9c7dadb03dddabc8a9ba04a02322601d16b28748ea4df4d9c2150843fecfba68 */ .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에서 상태를 관리하고, 간단하면서도 기능적인 영화 탐색 경험을 만드는 방법을 보여줍니다.
디자인을 자유롭게 맞춤화하고 사용자 리뷰나 영화 평가와 같은 기능을 추가하여 더욱 역동적으로 만들어 보세요!
Abhishek Gurjar는 실용적이고 기능적인 웹 애플리케이션 제작에 열정을 쏟는 헌신적인 웹 개발자입니다. GitHub에서 더 많은 프로젝트를 확인해 보세요.
위 내용은 React를 사용하여 Movie Finder 웹사이트 구축하기의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!