◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。
在这篇博文中,我们将探索如何使用 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></header><outlet></outlet></themeprovider> ); }; export default app;
标题组件允许用户在浅色和深色主题之间切换并显示应用程序标题。
import { usetheme } from "../hooks/usetheme" export default function header() { const [isdark, setisdark] = usetheme(); return ( <header classname="{`header-container" :><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- :></i> {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" :><div classname="search-filter-container"> <searchbar setquery="{setquery}"></searchbar><selectmenu setquery="{setquery}"></selectmenu> </div> <countrieslist query="{query}"></countrieslist></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></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}"></countrycard> ))} </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" :> <h3>country not found</h3> <link to="/">back to home </div> ); } if (!countrydata) { return <countrydetailshimmer></countrydetailshimmer>; } return ( <div classname="{`country-detail-container" :> <link to="/" classname="back-button"> <i classname="fa-solid fa-arrow-left"></i> back <div classname="country-detail-content"> @@##@@ <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"> @@##@@ <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> </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 上查看他的更多项目。
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。