React 18: Button click in map function to reflect information only related to one item and not all items

Viewed 19

I am new to React and using React 18 in this app. My problem is that if I click one button inside a map function, it reflects information about all the items. I want only that item information to show for which I clicked the button. The isShown === true part in the CountryInfo.js file is what should reflect only one item; currently clicking the show button shows all item information on the UI (I don't want this to happen). How do I do this?

Visually, this is my UI,

input to find countries

If you see the image above, clicking any show button returns all countries information, which should not happen.

Below is my code:

App.js

import { useState, useEffect } from 'react';
import axios from "axios";
import CountryInfo from './components/CountryInfo';

const App = () => {
    const [countries, setCountries] = useState([]);
    const [searchCountry, setSearchCountry] = useState("");

    const handleCountryChange = event => {
        setSearchCountry(event.target.value);
    }

    const getAllCountriesData = () => {
        axios.get("https://restcountries.com/v3.1/all")
            .then(response => {
                setCountries(response.data);
            })
    }

    useEffect(() => {
        getAllCountriesData();
    }, []);


    return (
        <>
            <h2>Data for countries</h2>
            find countries:
            <input value={searchCountry} onChange={handleCountryChange} />

            {searchCountry.length > 0 && <CountryInfo countries={countries} searchCountry={searchCountry} />}
        </>
    )
}

export default App;

CountryInfo.js

import React from "react";
import { useState } from "react";

const CountryInfo = ({ countries, searchCountry }) => {
    const [isShown, setIsShown] = useState(false);

    let filteredList = countries.filter(country =>
        country.name.common.toLowerCase().includes(searchCountry.toLowerCase()));

    const handleClick = () => {
        setIsShown(true);
    }

    if (filteredList.length > 10) {
        return <div>Too many matches, specify another filter</div>
    }
    else {
        return filteredList.map(country => {
            return (
                <>
                    <div key={country.name.common}>
                        {!isShown &&
                            <div>
                                {country.name.common}
                                <button type="submit" onClick={handleClick}>show</button>
                            </div>
                        }

                        {isShown &&
                            <div key={country.name.common}>
                                <h2>{country.name.common}</h2>

                                <p>
                                    Capital: {country.capital}
                                    {'\n'}
                                    Area: {country.area}
                                </p>

                                Languages:
                                <ul>
                                    {
                                        Object.values(country.languages)
                                            .map((language, index) => <li key={index}>{language}</li>)
                                    }
                                </ul>

                                <img src={country.flags.png} alt={`${country.name.common} flag`} height={150} />
                            </div>
                        }
                    </div>
                </>
            )
        })
    }
}


export default CountryInfo;
0 Answers
Related