Maison  >  Article  >  interface Web  >  Créer une application Country Finder avec React

Créer une application Country Finder avec React

DDD
DDDoriginal
2024-09-13 14:15:261005parcourir

Building a Country Finder Application with React

Introduction

Dans cet article de blog, nous explorerons comment créer une application Country Finder à l'aide de React. Cette application permet aux utilisateurs de rechercher des pays, de les filtrer par région et d'afficher des informations détaillées sur chaque pays. Nous utiliserons les hooks et le contexte de React pour gérer l'état et les thèmes, et nous intégrerons l'API REST Countries pour récupérer les données des pays.

Aperçu du projet

L'application Country Finder fournit une interface interactive où les utilisateurs peuvent :

  • Recherchez des pays par nom.
  • Filtrer les pays par région.
  • Affichez des informations détaillées sur chaque pays, y compris son drapeau, sa population et bien plus encore.

Caractéristiques

  • Barre de recherche : permet aux utilisateurs de rechercher des pays par nom.
  • Filtrer par région : menu déroulant pour filtrer les pays en fonction de leur région.
  • Détails du pays : affiche des informations détaillées sur un pays sélectionné.
  • Changement de thème : basculez entre les thèmes clairs et sombres.

Technologies utilisées

  • React : bibliothèque JavaScript pour créer des interfaces utilisateur.
  • API REST Countries : fournit des données sur les pays.
  • CSS : Pour styliser l'application.
  • React Router : Pour naviguer entre les pages et passer l'état.

Structure du projet

Le projet est organisé en plusieurs composantes :

  • App.js : composant principal qui inclut l'en-tête et la sortie pour le routage.
  • Header.js : affiche le titre de l'application et le bouton bascule du thème.
  • Home.js : page principale avec des options de recherche et de filtrage, ainsi qu'une liste de pays.
  • SearchBar.js : Composant de recherche de pays.
  • SelectMenu.js : Menu déroulant pour filtrer les pays par région.
  • CountriesList.js : affiche une liste de pays en fonction des critères de recherche et de filtrage.
  • CountryCard.js : Affiche un résumé de chaque pays.
  • CountryDetail.js : affiche des informations détaillées sur un pays sélectionné.
  • CountryDetailShimmer.js : chargement d'un espace réservé pour les détails du pays.
  • Error.js : Composant de gestion des erreurs pour les routes.

Installation

  1. Cloner le dépôt :
   git clone https://github.com/abhishekgurjar-in/country-finder.git
   cd country-finder
  1. Installer les dépendances :
   npm install
  1. Démarrez le serveur de développement :
   npm start

Usage

  1. Rechercher un pays : saisissez le nom d'un pays dans la barre de recherche pour filtrer la liste des pays.
  2. Filtrer par région : sélectionnez une région dans le menu déroulant pour voir les pays de cette région.
  3. Afficher les détails : cliquez sur la carte d'un pays pour afficher des informations détaillées sur le pays.

Explication du code

App.js

Le composant App enveloppe les composants Header et Outlet dans un ThemeProvider, gérant l'état du thème dans l'application.

import Header from "./components/Header";
import { Outlet } from "react-router-dom";
import "./App.css";
import { ThemeProvider } from "./contexts/ThemeContext";

const App = () => {
  return (
    <ThemeProvider>
      <Header />
      <Outlet />
    </ThemeProvider>
  );
};

export default App;

En-tête.js

Le composant Header permet aux utilisateurs de basculer entre les thèmes clairs et sombres et affiche le titre de l'application.

import { useTheme } from "../hooks/useTheme"

export default function Header() {
  const [isDark, setIsDark] =  useTheme();

  return (
    <header className={`header-container ${isDark ? 'dark' : ''}`}>
      <div className="header-content">
        <h2 className="title">
          <a href="/">Country Finder</a>
        </h2>
        <p className="theme-changer" onClick={() => {
          setIsDark(!isDark);
          localStorage.setItem('isDarkMode', !isDark);
        }}>
          <i className={`fa-solid fa-${isDark ? 'sun' : 'moon'}`} />
            {isDark ? 'Light' : 'Dark'} Mode
        </p>
      </div>
    </header>
  )
}

Accueil.js

Le composant Accueil contient la barre de recherche, le menu de filtrage et répertorie les pays en fonction des critères de recherche et de filtrage.

import React, { useState } from 'react';
import SearchBar from './SearchBar';
import SelectMenu from './SelectMenu';
import CountriesList from './CountriesList';
import { useTheme } from '../hooks/useTheme';

export default function Home() {
  const [query, setQuery] = useState('');
  const [isDark] = useTheme();

  return (
    <main className={`${isDark ? 'dark' : ''}`}>
      <div className="search-filter-container">
        <SearchBar setQuery={setQuery} />
        <SelectMenu setQuery={setQuery} />
      </div>
      <CountriesList query={query} />
    </main>
  )
}

SearchBar.js

Le composant SearchBar gère les saisies utilisateur pour la recherche de pays.

import React from 'react';

export default function SearchBar({ setQuery }) {
  return (
    <div className="search-container">
      <i className="fa-solid fa-magnifying-glass"></i>
      <input
        onChange={(e) => setQuery(e.target.value.toLowerCase())}
        type="text"
        placeholder="Search for a country..."
      />
    </div>
  )
}

SelectMenu.js

Le composant SelectMenu fournit une liste déroulante pour filtrer les pays par région.

import React from 'react';

export default function SelectMenu({ setQuery }) {
  return (
    <select className="filter-by-region" onChange={(e) => setQuery(e.target.value.toLowerCase())}>
      <option hidden>Filter by Region</option>
      <option value="Africa">Africa</option>
      <option value="Americas">Americas</option>
      <option value="Asia">Asia</option>
      <option value="Europe">Europe</option>
      <option value="Oceania">Oceania</option>
    </select>
  )
}

Liste des pays.js

Le composant CountriesList récupère et affiche une liste de pays.

import React, { useEffect, useState } from 'react';
import CountryCard from './CountryCard';
import CountriesListShimmer from './CountriesListShimmer';

export default function CountriesList({ query }) {
  const [countriesData, setCountriesData] = useState([]);

  useEffect(() => {
    fetch('https://restcountries.com/v3.1/all')
      .then((res) => res.json())
      .then((data) => {
        setCountriesData(data);
      });
  }, []);

  if (!countriesData.length) {
    return <CountriesListShimmer />;
  }

  return (
    <div className="countries-container">
      {countriesData
        .filter((country) =>
          country.name.common.toLowerCase().includes(query) || country.region.toLowerCase().includes(query)
        )
        .map((country) => (
          <CountryCard
            key={country.name.common}
            name={country.name.common}
            flag={country.flags.svg}
            population={country.population}
            region={country.region}
            capital={country.capital?.[0]}
            data={country}
          />
        ))}
    </div>
  )
}

CountryDetail.js

Le composant CountryDetail récupère et affiche des informations détaillées sur un pays sélectionné.

import React, { useEffect, useState } from 'react';
import { Link, useLocation, useParams } from 'react-router-dom';
import { useTheme } from '../hooks/useTheme';
import CountryDetailShimmer from './CountryDetailShimmer';
import './CountryDetail.css';

export default function CountryDetail() {
  const [isDark] = useTheme();
  const params = useParams();
  const { state } = useLocation();
  const countryName = params.country;

  const [countryData, setCountryData] = useState(null);
  const [notFound, setNotFound] = useState(false);

  function updateCountryData(data) {
    setCountryData({
      name: data.name.common || data.name,
      nativeName: Object.values(data.name.nativeName || {})[0]?.common,
      population: data.population,
      region: data.region,
      subregion: data.subregion,
      capital: data.capital,
      flag: data.flags.svg,
      tld: data.tld,
      languages: Object.values(data.languages || {}).join(', '),
      currencies: Object.values(data.currencies || {})
        .map((currency) => currency.name)
        .join(', '),
      borders: [],
    });

    if (!data.borders) {
      data.borders = [];
    }

    Promise.all(
      data.borders.map((border) =>
        fetch(`https://restcountries.com/v3.1/alpha/${border}`)
          .then((res) => res.json())
          .then(([borderCountry]) => borderCountry.name.common)
      )
    ).then((borders) => {
      setTimeout(() =>
        setCountryData((prevState) => ({ ...prevState, borders }))
      );
    });
  }

  useEffect(() => {
    if (state) {
      updateCountryData(state);
      return;
    }

    fetch(`https://restcountries.com/v3.1/name/${countryName}?fullText=true`)


 .then((res) => res.json())
      .then(([data]) => {
        if (!data) {
          setNotFound(true);
        } else {
          updateCountryData(data);
        }
      })
      .catch(() => setNotFound(true));
  }, [countryName, state]);

  if (notFound) {
    return (
      <div className={`error-container ${isDark ? 'dark' : ''}`}>
        <h3>Country not found</h3>
        <Link to="/">Back to home</Link>
      </div>
    );
  }

  if (!countryData) {
    return <CountryDetailShimmer />;
  }

  return (
    <div className={`country-detail-container ${isDark ? 'dark' : ''}`}>
      <Link to="/" className="back-button">
        <i className="fa-solid fa-arrow-left" />
         Back
      </Link>
      <div className="country-detail-content">
        <img src={countryData.flag} alt={`${countryData.name} flag`} />
        <div className="country-detail-info">
          <h1>{countryData.name}</h1>
          <div className="details">
            <p><strong>Native Name:</strong> {countryData.nativeName}</p>
            <p><strong>Population:</strong> {countryData.population}</p>
            <p><strong>Region:</strong> {countryData.region}</p>
            <p><strong>Subregion:</strong> {countryData.subregion}</p>
            <p><strong>Capital:</strong> {countryData.capital}</p>
            <p><strong>Top Level Domain:</strong> {countryData.tld}</p>
            <p><strong>Languages:</strong> {countryData.languages}</p>
            <p><strong>Currencies:</strong> {countryData.currencies}</p>
            <p><strong>Border Countries:</strong> {countryData.borders.join(', ') || 'None'}</p>
          </div>
        </div>
      </div>
    </div>
  );
}

CountryDetailShimmer.js

Le composant CountryDetailShimmer affiche un espace réservé de chargement lors de la récupération des détails du pays.

import React from 'react';

export default function CountryDetailShimmer() {
  return (
    <div className="country-detail-shimmer">
      <div className="shimmer-img"></div>
      <div className="shimmer-info">
        <div className="shimmer-line name"></div>
        <div className="shimmer-line"></div>
        <div className="shimmer-line"></div>
        <div className="shimmer-line"></div>
        <div className="shimmer-line"></div>
      </div>
    </div>
  );
}

CountryCard.js

Le composant CountryCard affiche un bref aperçu de chaque pays.

import React from 'react';
import { Link } from 'react-router-dom';

export default function CountryCard({ name, flag, population, region, capital, data }) {
  return (
    <div className="country-card">
      <img src={flag} alt={`${name} flag`} />
      <h3>{name}</h3>
      <p><strong>Population:</strong> {population}</p>
      <p><strong>Region:</strong> {region}</p>
      <p><strong>Capital:</strong> {capital}</p>
      <Link to={`/country/${name}`} state={data}>
        <button>More Details</button>
      </Link>
    </div>
  );
}

PaysListeShimmer.js

Le composant CountriesListShimmer affiche un espace réservé de chargement lors de la récupération de la liste des pays.

import React from 'react';

export default function CountriesListShimmer() {
  return (
    <div className="countries-list-shimmer">
      {Array.from({ length: 10 }).map((_, index) => (
        <div key={index} className="shimmer-card"></div>
      ))}
    </div>
  );
}

Démo en direct

Vous pouvez voir une démo en direct de l'application Country Finder en visitant Country Finder Demo.

Conclusion

Dans ce projet, nous avons créé une application Country Finder à l'aide de React qui permet aux utilisateurs de rechercher des pays, de les filtrer par région et d'afficher des informations détaillées. Nous avons intégré l'API REST Countries et utilisé les hooks et le contexte de React pour gérer l'état et les thèmes.

Crédits

  • Réagir : Réagir
  • API Pays REST : Pays REST
  • Police géniale : Police géniale

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!

Déclaration:
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