PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0

Thursday, October 13, 2022

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

 October 13, 2022     axios, javascript, reactjs     No comments   

Issue

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!


Solution

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})
   }
  


Answered By - AttemptedMastery
Answer Checked By - David Goodson (PHPFixing Volunteer)
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Newer Post Older Post Home

0 Comments:

Post a Comment

Note: Only a member of this blog may post a comment.

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
Comments
Atom
Comments

Copyright © PHPFixing