React を使用した Country Finder アプリケーションの構築

DDD
リリース: 2024-09-13 14:15:26
オリジナル
1036 人が閲覧しました

Building a Country Finder Application with React

導入

このブログ投稿では、React を使用して Country Finder アプリケーションを構築する方法を検討します。このアプリケーションを使用すると、ユーザーは国を検索し、地域でフィルターし、各国の詳細情報を表示できます。 React のフックとコンテキストを利用して状態とテーマを管理し、REST Countries API と統合して国データを取得します。

プロジェクト概要

Country Finder アプリケーションは、ユーザーが次のことができる対話型インターフェイスを提供します。

  • 国を名前で検索します。
  • 地域ごとに国をフィルタリングします。
  • 国旗、人口など、各国に関する詳細情報を表示します。

特徴

  • 検索バー: ユーザーは名前で国を検索できます。
  • 地域でフィルター: 地域に基づいて国をフィルターするドロップダウン メニュー。
  • 国の詳細: 選択した国に関する詳細情報が表示されます。
  • テーマの切り替え: 明るいテーマと暗いテーマを切り替えます。

使用されている技術

  • React: ユーザー インターフェイスを構築するための JavaScript ライブラリ。
  • REST Countries API: 国に関するデータを提供します。
  • CSS: アプリケーションのスタイルを設定します。
  • React Router: ページ間の移動と状態の受け渡し用。

プロジェクトの構造

プロジェクトはいくつかのコンポーネントで構成されています:

  • App.js: ルーティング用のヘッダーとアウトレットを含むメインコンポーネント。
  • Header.js: アプリケーションのタイトルとテーマの切り替えボタンを表示します。
  • Home.js: 検索とフィルターのオプション、および国のリストを含むメイン ページ。
  • SearchBar.js: 国を検索するためのコンポーネント。
  • SelectMenu.js: 地域別に国をフィルタリングするためのドロップダウン メニュー。
  • CountriesList.js: 検索およびフィルター基準に基づいて国のリストを表示します。
  • CountryCard.js: 各国の概要を表示します。
  • CountryDetail.js: 選択した国に関する詳細情報を表示します。
  • CountryDetailShimmer.js: 国の詳細のプレースホルダーを読み込みます。
  • Error.js: ルートのエラー処理コンポーネント。

インストール

  1. リポジトリのクローンを作成します:
   git clone https://github.com/abhishekgurjar-in/country-finder.git
   cd country-finder
ログイン後にコピー
  1. 依存関係をインストールします:
   npm install
ログイン後にコピー
  1. 開発サーバーを起動します:
   npm start
ログイン後にコピー

使用法

  1. 国の検索: 検索バーに国名を入力して、国のリストをフィルタリングします。
  2. 地域でフィルター: ドロップダウン メニューから地域を選択すると、その地域の国が表示されます。
  3. 詳細を表示: 国カードをクリックすると、その国の詳細情報が表示されます。

コードの説明

App.js

App コンポーネントは、ThemeProvider 内で Header コンポーネントと Outlet コンポーネントをラップし、アプリケーション全体でテーマの状態を管理します。

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;
ログイン後にコピー

ヘッダー.js

Header コンポーネントを使用すると、ユーザーは明るいテーマと暗いテーマを切り替え、アプリケーションのタイトルを表示できます。

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>
  )
}
ログイン後にコピー

ホーム.js

ホーム コンポーネントには、検索バー、フィルター メニューが含まれており、検索およびフィルター基準に基づいて国のリストが表示されます。

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>
  )
}
ログイン後にコピー

サーチバー.js

SearchBar コンポーネントは、国を検索するためのユーザー入力を処理します。

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>
  )
}
ログイン後にコピー

セレクトメニュー.js

SelectMenu コンポーネントは、地域ごとに国をフィルタリングするためのドロップダウンを提供します。

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>
  )
}
ログイン後にコピー

国リスト.js

CountriesList コンポーネントは、国のリストを取得して表示します。

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

CountryDetail コンポーネントは、選択した国に関する詳細情報を取得して表示します。

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

CountryDetailShimmer コンポーネントは、国の詳細を取得する際に読み込み中のプレースホルダーを表示します。

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

CountryCard コンポーネントには、各国の簡単な概要が表示されます。

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>
  );
}
ログイン後にコピー

国リストShimmer.js

CountriesListShimmer コンポーネントは、国のリストを取得するときに読み込み中のプレースホルダーを表示します。

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>
  );
}
ログイン後にコピー

ライブデモ

Country Finder デモにアクセスすると、 Country Finder アプリケーションのライブ デモを表示できます。

結論

このプロジェクトでは、React を使用して、ユーザーが国を検索し、地域でフィルターし、詳細情報を表示できる Country Finder アプリケーションを構築しました。私たちは REST Countries API と統合し、React のフックとコンテキストを使用して状態とテーマを管理しました。

クレジット

  • 反応: 反応
  • REST 国 API: REST 国
  • 素晴らしいフォント: 素晴らしいフォント

著者

Abhishek Gurjar は、実用的で機能的な Web アプリケーションの作成に情熱を注ぐ専任の Web 開発者です。 GitHub で彼のプロジェクトをさらにチェックしてください。

以上がReact を使用した Country Finder アプリケーションの構築の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート