Maison > interface Web > tutoriel CSS > Créer un site Web de recherche de films à l'aide de React

Créer un site Web de recherche de films à l'aide de React

DDD
Libérer: 2024-09-13 12:39:34
original
585 Les gens l'ont consulté

Building a Movie Finder Website using React

Introduction

Dans ce blog, nous allons parcourir le processus de création d'un site Web Movie Finder à l'aide de React et de l'API OMDB. Le site Web permet aux utilisateurs de parcourir les films par catégories telles que Avengers, Star Wars et Series, et de rechercher des films à l'aide de requêtes spécifiques. Chaque film a sa page de détails, ce qui permet d'en savoir plus sur vos films préférés.

Aperçu du projet

Le

Site Web Movie Finder permet aux utilisateurs de :

  • Parcourez les catégories comme Avengers et Star Wars.
  • Recherchez des films par mots-clés.
  • Affichez des informations détaillées sur le film (affiche, genre, réalisateur, acteurs, etc.).
  • Naviguez facilement sur le site Web avec un design épuré et moderne.

Caractéristiques

  • Récupérez les données de manière dynamique à l'aide de l'API OMDB.
  • Conception réactive pour une meilleure expérience utilisateur.
  • Fonctionnalité de recherche qui fournit des résultats instantanés.
  • Chargement des indicateurs pendant la récupération des données.
  • Affichez les détails des films individuels sur une page séparée.

Technologies utilisées

  • React : bibliothèque frontale pour créer des composants d'interface utilisateur.
  • React Router : Pour la navigation et le routage.
  • Axios : Pour effectuer des requêtes HTTP vers l'API OMDB.
  • API OMDB : pour récupérer les détails du film.
  • CSS : Pour styliser l'application.

Structure du projet

Voici la structure des répertoires du projet :

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
Copier après la connexion

Installation

  1. Cloner le dépôt :

    git clone https://github.com/abhishekgurjar-in/movie-finder.git
    cd movie-finder
    
    Copier après la connexion
  2. Installer les dépendances :

    npm install
    
    Copier après la connexion
  3. Obtenez votre clé API depuis l'API OMDB.

  4. Créez un fichier .env à la racine du projet et ajoutez votre clé API :

    REACT_APP_OMDB_API_KEY=yourapikey
    
    Copier après la connexion
  5. Exécuter le projet :

    npm start
    
    Copier après la connexion

Usage

1. Page d'accueil

La Page d'accueil présente deux catégories de films : Avengers et Star Wars. Lorsque l'utilisateur clique sur une fiche de film, il est redirigé vers la page détaillée du film.

Extrait de code de 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;

Copier après la connexion

2. Fonctionnalité de recherche

L'utilisateur peut rechercher n'importe quel film en utilisant la barre de recherche en haut du site Web. Les résultats de la recherche sont récupérés à partir de l'API OMDB en fonction de la requête de l'utilisateur.

Extrait de code de 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;

Copier après la connexion

3. Page de détails du film

Lorsqu'un utilisateur clique sur un film, il est redirigé vers la page de détail du film. Cette page affiche le titre du film, l'affiche, l'intrigue, les acteurs et plus encore.

Extrait de code de 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;

Copier après la connexion

4. Pages de films et de séries

Les pages

Movies.js et Series.js répertorient respectivement les films et les séries télévisées.

Extrait de code de 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;
Copier après la connexion

Extrait de code de 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;
Copier après la connexion

5. Composant de barre de navigation

Le composant Navbar permet aux utilisateurs de naviguer entre différentes pages et d'effectuer une recherche.

Navbar.js mis à jour

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;
Copier après la connexion

6. Composant de pied de page

Le composant Footer fournit un simple message de pied de page.

Pied de page.js

import React from 'react';

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

export default Footer;
Copier après la connexion
*{
  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;
}

Copier après la connexion

Démo en direct

Vous pouvez consulter la démo en direct du site Web Movie Finder ici.

Conclusion

Dans ce blog, nous avons appris à créer un site Web Movie Finder à l'aide de React, React Router et Axios. Ce projet montre comment interagir avec une API publique, gérer l'état dans React et créer une expérience de navigation de films simple mais fonctionnelle.

N'hésitez pas à personnaliser le design et à ajouter plus de fonctionnalités, comme des avis d'utilisateurs ou des classements de films, pour le rendre plus dynamique !


Crédits

  • API OMDB
  • Réagir
  • Réagir le routeur

Auteur

Abhishek Gurjar est un développeur Web dévoué et passionné par la création d'applications Web pratiques et fonctionnelles. Découvrez plus de ses projets sur GitHub.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal