reactjsfetchpromise.all

Fetch to return only one value from mapped urls


I'm in the process of lifting the state up in order to compare ids between the single pokemonCard and the clicked card and make it so that only the clicked card will change from 'captured' to 'not captured'.

At the moment when I try to fetch a single pokemonCard from the mapped urls I currently get all the cards. What I want would basically be setPokemonCard(res[0]) but of course that 0 needs to be dynamic. How can I achieve this?

WARNING: Pokedex and PokemonCard currently still have part of the code I've been lifting up (like the fetch and the url) so that I can see what's happening.

import Header from './components/Header';
import Footer from './components/Footer';
import Pokedex from './pages/Pokedex';
//import PokemonCard from './components/PokemonCard'
import Pokemon from './pages/Pokemon';
import Dropdown from './components/Dropdown';
import { useState, useEffect } from 'react';
import { Routes, Route, BrowserRouter as Router } from 'react-router-dom';
import { PokemonContext } from './context/PokemonContext'

function App() {
  const [pokemons, setPokemons] = useState([]);
  const [captured, setCaptured] = useState(false)
  const URL = 'https://pokeapi.co/api/v2/pokemon/?limit=151';
  const [pokemonCard, setPokemonCard] = useState([])
  const pokCardURL = pokemons.map(pokemon => pokemon.url)
  // console.log(pokCardURL)
  //console.log(pokemons)

  const fetchingPokemons = async () => {
    const res = await fetch(URL);
    const data = await res.json();
    // console.log(data)
    setPokemons(data.results)
  }

  useEffect(() => {
    fetchingPokemons()
  }, [URL])

  const fetchingPokemonCard = async () => {
    //const res = await fetch(pokCardURL);
    const res = await Promise.all(pokCardURL.map(url => fetch(url).then((res)=> res.json())));
    //const data = await res.json();

    setPokemonCard(res[0])
  }

  useEffect(() => {
    fetchingPokemonCard()

  }, [pokCardURL])

  //console.log(pokemonCard)


  const toggleCaptured = () => {
    console.log(pokemonCard) //compare pokemonCard.id === card clicked
  }

  //const toggleCaptured = () => setCaptured(captured => !captured);

  const providerValue = {
    pokemons,
    captured,
    toggleCaptured,
  }

  return (
    <PokemonContext.Provider value={providerValue}>
      <Router>
        <Header />
        <Dropdown />
        <main className='main'>
          <Routes>
            <Route exact path="/" element={<Pokedex />} />
            <Route path="/pokemon/:id" element={<Pokemon />} />
          </Routes>
        </main>
        <Footer />
      </Router>
    </PokemonContext.Provider>
  )
}

export default App;

import React, { useState, useEffect } from 'react'
import PokemonCard from '../components/PokemonCard';
import { useContext } from 'react';
import { PokemonContext } from '../context/PokemonContext';

const Pokedex = () => {
const {pokemons} = useContext(PokemonContext)
    // const [pokemons, setPokemons] = useState([]);
    //console.log(captured)

    // const URL = 'https://pokeapi.co/api/v2/pokemon/?limit=151';

    // const fetchingPokemons = async () => {
    //     const res = await fetch(URL);
    //     const data = await res.json();
    //     // console.log(data)
    //     setPokemons(data.results)
    // }

    // useEffect(() => {
    //     fetchingPokemons()
    // }, [URL])

    return (
        <>
            {pokemons.map((pokemon) => {
                // console.log(pokemon)
                return (
                    <>
                        <div style={{ width: '20%' }} key={pokemon.name}>
                            <PokemonCard
                                pokemon={pokemon}
                                name={pokemon.name}
                                url={pokemon.url}
                                key={pokemon.name}
                            />

                        </div>
                    </>
                )
            })}
        </>
    )
}

export default Pokedex

import React, { useState, useEffect } from 'react';
import { Link } from 'react-router-dom';
//import Checkbox from './Checkbox';
import PokemonIcon from './PokemonIcon';
import { useContext } from 'react';
import { PokemonContext } from '../context/PokemonContext';

const PokemonCard = (props) => {
    const { url } = props
    const { captured, toggleCaptured } = useContext(PokemonContext)
    //console.log(pokemonCard)
    const URL = url
     const [pokemonCard, setPokemonCard] = useState([])
    //   const [captured, setCaptured] = useState(false)
    //  const [filteredPokemons, setFilteredPokemons] = useState([])

    //  const getFilteredPokemon = (id) => {
    //      if(captured) {
    //          filteredPokemons.push(pokemonCard)
    //          //setFilteredPokemons([...filteredPokemons, filteredPokemons])
    //         console.log(filteredPokemons)
    //         }
    //     setFilteredPokemons(pokemonCard.id === id)
    //     console.log(filteredPokemons)
    // }


    //  const toggleCaptured = () => setCaptured(captured => !captured);


    const fetchingPokemonCard = async () => {
        const res = await fetch(URL);
        const data = await res.json();
        //console.log(data)
        setPokemonCard(data)
    }

    useEffect(() => {
        fetchingPokemonCard()

    }, [URL])

    return (
        <>
            <div className='pokemon-card' style={{
                height: '250px',
                maxWidth: '250px',
                margin: '1rem',
                boxShadow: '5px 5px 5px 4px rgba(0, 0, 0, 0.3)',
                cursor: 'pointer',
            }} >
                <Link to={{ pathname: `/pokemon/${pokemonCard.id}` }} state={{ pokemon: pokemonCard, captured }} style={{ textDecoration: 'none', color: '#000000' }}>
                    <div style={{ padding: '20px', display: 'flex', justifyContent: 'center', alignItems: 'center' }} >
                        {/* <PokemonIcon img={pokemonCard.sprites?.['front_default']} /> */}
                        <img style={{
                            height: '100px',
                            width: '100px',
                        }} src={pokemonCard.sprites?.['front_default']} alt='pokemon' />
                    </div>
                </Link>
                <div style={{ textAlign: 'center' }}>
                    <h1 >{pokemonCard.name}</h1>
                    <label >
                        <input
                            type='checkbox'
                            captured='false'
                            onChange={toggleCaptured}
                        />
                        <span style={{ marginLeft: 8 }}>
                            {captured === false ? 'Not captured!' : 'Captured!'}</span>

                    </label>
                </div>
            </div>
            <div>
            </div>
        </>
    )
}

export default PokemonCard

Solution

  • In your fetchingPokemonCard, just filter the res to match your pokemonCard.id. I don't know what your response looks like so I can't write the filter for you.