Brad G.
Brad G.

Reputation: 101

How should I structure my axios.get in my file so to not have repeated "cannot read properties of undefined (reading '0')?

I managed to fix one of the things that was spotted in my previous post. Which was to switch the brackets on a useState declaration. But I ran into another problem, it seems to be related to how my code is laid out within the useEffect. Should I delete it? Or should I shift my code around to allow the pkmnResponse to be created and loaded? Before it was inside of a try/catch, and the axios.get call had an await attached to it before I took out based on some digging in StackOverflow. I noticed when I just saved my code and it refreshed on its own, I was able to console.log stats from it, but it still gave me this error:

Uncaught (in promise) TypeError: Cannot read properties of undefined (reading '0') at getPkmnStats (PkmnStats.js:62:1)

The page loads without any data, just a broken image link and blank attributes.

Here is the code for PkmnStats:

import axios from 'axios';
import { useParams } from 'react-router-dom';
import loading from './loading.gif';


function PkmnStats() {

    const [isLoading, setIsLoading] = useState(true);
    const [pkmnResponse, setPkmnResponse] = useState();
    const [pkmnStat, setPkmnStat] = useState(
        {
            name:'',
            index:'',
            imageUrl:'',
            types:[''],
            description:'',
            stats:{

                hp:'',
                attack:'',
                defense:'',
                speed:'',
                specialAttack:'',
                specialDefense:''       
            },
            height:'',
            weight:'',
            abilities:['']
        }

    );

    const params = useParams()
    const index = params.index
    const name = params.name

    const pkmnUrl = `https://pokeapi.co/api/v2/pokemon/${index}`
    const pkmnSpecies = `https://pokeapi.co/api/v2/pokemon-species/${index}/`
    const imageUrl = `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${index}.png`


   

    useEffect(() => {

        const getPkmnStats = async () => {

            
                    axios.get(pkmnUrl).then((response) => {

                        setIsLoading(true);
                        setPkmnResponse(response.data)
                        //const species = pkmnResponse.data.species;
                    

                    }).catch(error => {
                        setIsLoading(false);
                        console.log("An error happened", error);
                    });
                   
                    console.log( "heres the response data " + pkmnResponse.stats[0].base_stat)

                    

                    const hp = pkmnResponse.stats[0].base_stat
                    const attack = pkmnResponse.stats[1].base_stat
                    const defense = pkmnResponse.stats[2].base_stat
                    const speed = pkmnResponse.stats[5].base_stat
                    const specialAttack = pkmnResponse.stats[3].base_stat
                    const specialDefense = pkmnResponse.stats[4].base_stat
                    
                    
            
                    // pkmnResponse.data.stats.map((stat) =>  {
                    //     if(stat.stat.name === 'hp'){
                    //         hp = stat['base_stat'];
                    //     }
                    //     if(stat.stat.name === 'attack'){
                    //         attack = stat['base_stat'];
                    //     }
                    //     if(stat.stat.name === 'defense'){
                    //         defense = stat['base_stat'];
                    //     }
                    //     if(stat.stat.name === 'speed'){
                    //         speed = stat['base_stat'];
                    //     }
                    //     if(stat.stat.name === 'special-attack'){
                    //         specialAttack = stat['base_stat'];
                    //     }
                    //     if(stat.stat.name === 'special-defense'){
                    //         specialDefense = stat['base_stat'];
                    //     }
                    
        
                    // });
                    const height = Math.round((pkmnResponse.data.height * 0.328084 + 0.0001) * 100)/100;
                    const weight = Math.round((pkmnResponse.data.weight * 0.220462 + 0.0001) * 100)/100;
            
                    const types  = pkmnResponse.data.types.map(types => {return types.type.name});

                    const abilities = pkmnResponse.data.abilities.map(abilities => {
                    return abilities.ability.name
                    });
                    // getPkmnDescription(pkmnSpecies);

                    let description ='';

                    const getDesc =  axios.get(pkmnSpecies).then(() => {

                        getDesc.data.flavor_text_entries.some(flavor => {
            
                        if (flavor.language.name === 'en') {
                            description = flavor.flavor_text;
                            return description;
                            }
                        });
                        }).catch(error => {
                            setIsLoading(false);
                            console.log("An error happened", error);
                        });
                        
                        
                        setPkmnStat({  index, name, imageUrl, types, stats: {hp, attack, defense, speed, specialAttack, specialDefense}, height, weight, abilities, description})
                    
                        
        }
  
        
        getPkmnStats();
        
    },[])

   
    return (
            <>
            {isLoading ? (
                <div className='mx-auto w-fit h-screen p-6  md:w-3/5'>
                    <div className='flex flex-col items-center justify-center md:flex-col lg:flex-row'>
                            <div className='flex flex-col items-center '>
                                <p className='text-5xl md:text-6xl'>{params.name}</p>
                                <img className=" w-32 h-32 md:w-64 md:h-64 " src={pkmnStat.imageUrl} alt={pkmnStat.name} />
                                <div className='flex flex-row '>
                                    <div>{pkmnStat.types[0] ? pkmnStat.types[0] : null}</div>
                                    <div>{pkmnStat.types[1] ? pkmnStat.types[1] :null}</div>
                                </div>
                                <p>Height: {pkmnStat.height} ft.</p>
                                <p>Weight: {pkmnStat.weight} lbs.</p>
                            </div>
                            <div className='flex flex-col items-center '>
                                <p className='text-center my-5'>{pkmnStat.description} </p>
                                
                                <p>Abilities: {pkmnStat.abilities}</p>
                                <div className='flex flex-col items-center mt-4 '>
                                        <p> HP: {pkmnStat.stats.hp}</p>
                                        <p> Attack: {pkmnStat.stats.attack}</p>
                                        <p>Defense: {pkmnStat.stats.defense}</p>
                                        <p>Speed: {pkmnStat.stats.speed}</p>
                                        <p>Spec.Attack: {pkmnStat.stats.specialAttack}</p>
                                        <p>Spec.Defense: {pkmnStat.stats.specialDefense}</p>
                                </div>
                        </div>
                    </div>
                </div>
                ) : ( <img src={loading} className="mx-auto bg-platnium" alt="loading gif"/>) }
            </> 
    )
    
}
export default PkmnStats

PkmnCard and App for reference:

PkmnCard


import loading from './loading.gif'
import {Link} from 'react-router-dom'


const PkmnCard = ({pokemon}) => {

    const index = pokemon.url.split('/')[pokemon.url.split('/').length - 2];
    const sprite =`https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${index}.png`;
    
    return (
     
        <Link to={`/pokemon/${pokemon.name}/${index}` }>
            {pokemon ? (<div className='flex flex-col h-64  items-center p-10 rounded-xl  shadow-lg hover:shadow-2xl hover:border-stone-700 bg-white select-none '>
                <h3 className='text-center capitalize'>{pokemon.name}</h3>
                
                {pokemon.imageLoading ? (<img src={loading} className="mx-auto w-10 h-10" alt="loading gif"/>) :null}
                <img className='mx-auto' style={pokemon.tooManyRequests ? {display: "none"} : pokemon.imageLoading ? null : {display: "block"}} src={sprite} alt={pokemon.name} onLoad={() => ({imageLoading: false})} onError={ () => ({ tooManyRequests: true})} />
                {pokemon.tooManyRequests ? (<h6 className='mx-auto bg-red-600'> <span className='text-white'>Too Many Requests </span></h6>) :null }
                <h3 className="text-center">-No.{index}-</h3>
            
            </div>):  (<img src={loading} className="mx-auto bg-platnium" alt="loading gif"/>)}
        </Link>
     
    )


  
}
export default PkmnCard

App

import React from 'react'
import { Route, BrowserRouter, Routes} from 'react-router-dom'
import Navbar from './components/Navbar'
import PkmnList from './components/PkmnList'
import PkmnStats from './components/PkmnStats'



function App (){

    return (  
      <BrowserRouter>
          <div className="w-full">
            <Navbar/>
          
              <Routes>
                <Route path="/" element={<PkmnList/>} />
                <Route path="/pokemon/:name/:index"  element={<PkmnStats/>} />
              </Routes>
            
          </div>
      </BrowserRouter>
    )


  }
export default App;

Any help with understanding what I did wrong and how/why to something else is appreciated!

Upvotes: 0

Views: 134

Answers (1)

AttemptedMastery
AttemptedMastery

Reputation: 768

To quickly solve your problem, use useEffects's dependency array to listen for state changes in pkmResponse. Also, there's no reason to call getPkmStats() in useEffect twice - remove that last call. useEffect will call it on initial mount, so you are good there. Your useEffect block should look like this:

    useEffect(() => {


    },[pkmnResponse])

This will now give you access to pkmnResponse.

Also, here is a little light refactoring that helps readability. Instead of throwing everything in useEffect and cluttering it's block, I would modularize the fetch function and the pkmStat setters like this:

    useEffect(() => {
        getPkmnStats()
    },[pkmnResponse])


    const getPkmnStats = async () => {
        axios.get(pkmnUrl).then((response) => {
            setIsLoading(true);
            setPkmnResponse(response.data)
            pkmnStatSetter()
                        //const species = pkmnResponse.data.species;
         }).catch(error => {
            setIsLoading(false);
            console.log("An error happened", error);
        });
    }

    const pkmStatSetter = () => {
        const hp = pkmnResponse.stats[0].base_stat
        const attack = pkmnResponse.stats[1].base_stat
        const defense = pkmnResponse.stats[2].base_stat
        const speed = pkmnResponse.stats[5].base_stat
        const specialAttack = pkmnResponse.stats[3].base_stat
        const specialDefense = pkmnResponse.stats[4].base_stat
        const height = Math.round((pkmnResponse.data.height * 0.328084 + 0.0001) * 100)/100;
        const weight = Math.round((pkmnResponse.data.weight * 0.220462 + 0.0001) * 100)/100;
        const types  = pkmnResponse.data.types.map(types => {return types.type.name});
        const abilities = pkmnResponse.data.abilities.map(abilities => {
                return abilities.ability.name
        });
                    // getPkmnDescription(pkmnSpecies);
        let description ='';

        const getDesc =  axios.get(pkmnSpecies).then(() => {
        getDesc.data.flavor_text_entries.some(flavor => {
            if (flavor.language.name === 'en') {
                description = flavor.flavor_text;
                return description;
            }
        });
    }).catch(error => {
        setIsLoading(false);
        console.log("An error happened", error);
    });

    setPkmnStat({  index, name, imageUrl, types, stats: {hp, attack, defense, speed, specialAttack, specialDefense}, height, weight, abilities, description})
   }
  

Upvotes: 2

Related Questions