在這篇文章中,我們將探索如何使用 React 建立國家/地區尋找應用程式。該應用程式允許用戶搜尋國家/地區、按地區過濾它們以及查看有關每個國家/地區的詳細資訊。我們將利用 React 的鉤子和上下文來管理狀態和主題,並將與 REST 國家/地區 API 整合以獲取國家/地區資料。
國家/地區查找應用程式提供了一個互動式介面,使用者可以:
專案分為幾個組件:
git clone https://github.com/abhishekgurjar-in/country-finder.git cd country-finder
npm install
npm start
App 元件將 Header 和 Outlet 元件包裝在 ThemeProvider 中,管理整個應用程式的主題狀態。
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;
標題元件可讓使用者在淺色和深色主題之間切換並顯示應用程式標題。
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> ); }
您可以透過造訪國家/地區查找器示範來觀看國家/地區查找器應用程式的即時示範。
在這個專案中,我們使用 React 建立了一個國家/地區查找應用程序,允許用戶搜尋國家/地區、按地區過濾並查看詳細資訊。我們與 REST Country API 集成,並使用 React 的鉤子和上下文來管理狀態和主題。
Abhishek Gurjar 是一位專注的 Web 開發人員,熱衷於創建實用且功能性的 Web 應用程式。在 GitHub 上查看他的更多專案。
以上是使用 React 建立國家/地區查找應用程式的詳細內容。更多資訊請關注PHP中文網其他相關文章!