このブログ投稿では、React を使用して Country Finder アプリケーションを構築する方法を検討します。このアプリケーションを使用すると、ユーザーは国を検索し、地域でフィルターし、各国の詳細情報を表示できます。 React のフックとコンテキストを利用して状態とテーマを管理し、REST Countries API と統合して国データを取得します。
Country Finder アプリケーションは、ユーザーが次のことができる対話型インターフェイスを提供します。
プロジェクトはいくつかのコンポーネントで構成されています:
git clone https://github.com/abhishekgurjar-in/country-finder.git cd country-finder
npm install
npm start
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;
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> ) }
ホーム コンポーネントには、検索バー、フィルター メニューが含まれており、検索およびフィルター基準に基づいて国のリストが表示されます。
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 コンポーネントは、国を検索するためのユーザー入力を処理します。
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 コンポーネントは、地域ごとに国をフィルタリングするためのドロップダウンを提供します。
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> ) }
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 コンポーネントは、選択した国に関する詳細情報を取得して表示します。
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 コンポーネントは、国の詳細を取得する際に読み込み中のプレースホルダーを表示します。
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 コンポーネントには、各国の簡単な概要が表示されます。
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> ); }
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 のフックとコンテキストを使用して状態とテーマを管理しました。
Abhishek Gurjar は、実用的で機能的な Web アプリケーションの作成に情熱を注ぐ専任の Web 開発者です。 GitHub で彼のプロジェクトをさらにチェックしてください。
以上がReact を使用した Country Finder アプリケーションの構築の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。