I was asked to improve my app that when the names of multiple countries are shown on the page there is a button next to the name of the country, which when pressed shows the view for that country.
I attempted using conditional rendering and state management in my react code to show the data when the button is pressed however when I press the button nothing happens, the country I clicked’s data is not presented. I think there is a simpler way I just can’t seem to wrap my head around it. Here is my code:
App:
import SearchBar from "./Components/SearchBar";
import axios from "axios";
import { useState, useEffect } from "react";
import CountryList from "./Components/CountryList";
import CountryDetail from "./Components/CountryDetail";
const App = () => {
const [searchTerm, setSearchTerm] = useState("");
const [countries, setCountries] = useState([]);
const [show, setShow] = useState(false);
useEffect(() => {
if (searchTerm.trim() === "") {
setCountries([]);
return;
}
axios.get(`https://restcountries.com/v3/name/${searchTerm}`)
.then((response) => {
setCountries(response.data);
})
.catch((error) => {
console.error("Error fetching data: ", error);
setCountries([]);
});
}, [searchTerm]);
const toggleShow = (countryName) => {
console.log("Before toggle:", show);
setShow((prevShow) => {
const newShow = { ...prevShow };
newShow[countryName] = !newShow[countryName];
return newShow;
});
console.log("After toggle:", show);
};
return (
<div>
<h1>Country Information App</h1>
<SearchBar
searchTerm={searchTerm}
setSearchTerm={setSearchTerm}
/>
{countries.length > 10 && searchTerm ? (
<p>
Too many matches, please make your query
more specific.
</p>
) : countries.length === 0 && searchTerm ? (
null
) : (
<>
<CountryList
countries={countries}
searchTerm={searchTerm}
handleToggle={toggleShow}
/>
<CountryDetail
countries={countries}
searchTerm={searchTerm}
show={show}
/>
</>
)}
</div>
);
};
export default App;
Country List:
import React from "react";
const CountryList = ({ countries, searchTerm, handleToggle }) => {
if (countries.length > 10) {
return null;
}
const filteredCountries = countries.filter((country) =>
country.name.common
.toLowerCase()
.includes(searchTerm.toLowerCase())
);
return (
<div>
<ul>
{filteredCountries.map((country) => (
<li key={country.name.common}>
{country.name.common} {" "}
<button onClick={() => handleToggle(country.name.common)}>show</button>
</li>
))}
</ul>
</div>
);
};
export default CountryList;
Country Detail:
import React from "react";
const CountryDetail = ({ countries, searchTerm, show }) => {
if (countries.length === 0 || searchTerm === "") {
return null;
}
const filteredCountries = countries.filter(
(country) =>
country.name.common.toLowerCase() ===
searchTerm.toLowerCase()
);
if (filteredCountries.length === 0) {
return null;
}
const country = filteredCountries[0]; // Get the first matching country
return show ? (
<div>
<h2>{country.name.common}</h2>
<p>Capitals: {country.capital}</p>
<p>Area: {country.area} km²</p>
<h3>Languages</h3>
<ul>
{Object.values(country.languages).map(
(language, index) => (
<li key={index}>{language}</li>
)
)}
</ul>
<img src={country.flags[1]} alt={country.name.common} />
</div>
) : null;
};
export default CountryDetail;
Search Bar:
import React from "react";
const SearchBar = ({ searchTerm, setSearchTerm }) => {
const handleSearch = (event) => {
setSearchTerm(event.target.value);
};
return (
<div>
<label htmlFor="searchInput">
Search for a country:{" "}
</label>
<input
type="text"
placeholder="Enter search here.."
value={searchTerm}
onChange={handleSearch}
/>
</div>
);
};
export default SearchBar;
There are a few issues with this, but none that would cause the detailed information not to show. There are several places where the
CountryDetail
component rendersnull
, can you identify which one is being hit (you can useconsole.log
to figure it out)? My guess is that it has to do with how you definefilteredCountries
(search term must match country name exactly ).