How can I render the country data off of a button push?

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 renders null, can you identify which one is being hit (you can use console.log to figure it out)? My guess is that it has to do with how you define filteredCountries (search term must match country name exactly ).

    – 

Leave a Comment