Home > Back-end >  how to fix "Cannot read properties of undefined (reading 'front_default') "?
how to fix "Cannot read properties of undefined (reading 'front_default') "?

Time:06-19

I'm trying to display a piece of data from an API, I can reach it, but its giving me an unknown error I cant find an answer for it.
The error message :

Uncaught TypeError: Cannot read properties of undefined (reading 'front_default')

now, here's the funny part, when i first starting the page, its working, but if i refresh it, its giving me the error message on console and a white screen page.

this is the part of my code that don't seems to work.

                <img src={urlData.sprites.front_default}></img>

but, similar data can work, such as this line:

                <p> {urlData.id}</p>

I'll post the all code under here, but don't waste your time on reading it all, try focus on the error message and error origin in order of helping me identifying the problem.

dad component:

import './App.css';
import React, { useEffect, useState } from 'react';
import axios from 'axios';
import { PokemonContainer } from './components/Pokemon';

function App() {

  const [pokemonData, setPokemonData] = useState([]);
  const [loaded, setLoaded] = useState(false);

  const get_pokemon_data = async () => {
    setPokemonData((await axios.get('https://pokeapi.co/api/v2/pokemon?limit=9')).data.results);
  };

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

  useEffect(() => {
    setLoaded(true);
  }, [pokemonData]);

  if (loaded) {
    return (
      <div>
        {pokemonData.map((pokemon: any) => (
          <PokemonContainer key={pokemon.name} url={pokemon.url} />
        ))}
      </div>
    );
  } else {
    return (
      <div>
        <p>wait a minute</p>
      </div>
    )
  }


};

export default App;

child component :

import React, { useState, useEffect } from 'react';
import axios from 'axios';


export const PokemonContainer = (props: any) => {
    const [urlData, setURLData] = useState<any>([]);

    const [loaded, setLoaded] = useState<boolean>(false);



    useEffect(() => {
        const get_url_data = async () => {
            setURLData((await axios.get(props.url)).data);
        };
        get_url_data();
    }, []);

    useEffect(() => {
        setLoaded(true);
    }, [urlData]);

    if (loaded) {
        return (
            <div>
                <div key={urlData.name}>
                    <p> {urlData.name}</p>
                    <p> {urlData.id}</p>
                    <img src={urlData.sprites.front_default}></img>
                </div>
            </div>
        )
    } else {
        return (
            <div>
                <p>Loading...</p>
            </div>
        )
    }
};

CodePudding user response:

I think the problem is with your second useEffect

    useEffect(() => {
        setLoaded(true);
    }, [urlData]);

When component mounts this will set loaded to true but response is not fetched yet and urlData is still an empty array (which should be an empty object, I believe) therefore you get the error.

One way to fix this would be to check if urlData has been fetched inside the useEffect? if yes, then set loaded to true.

But I think this useEffecte is not needed at all. Instead of if(loaded) you could check for one urlData's properties, like: if(urlData.id)

child component:

import React, { useState, useEffect } from 'react';
import axios from 'axios';


export const PokemonContainer = (props: any) => {
    const [urlData, setURLData] = useState<any>([]);

    useEffect(() => {
        const get_url_data = async () => {
            setURLData((await axios.get(props.url)).data);
        };
        get_url_data();
    }, []);

    if (urlData.id) {
        return (
            <div>
                <div key={urlData.name}>
                    <p> {urlData.name}</p>
                    <p> {urlData.id}</p>
                    <img src={urlData.sprites.front_default}></img>
                </div>
            </div>
        )
    } else {
        return (
            <div>
                <p>Loading...</p>
            </div>
        )
    }
};

Or you can do it like:

import React, { useState, useEffect } from 'react';
import axios from 'axios';

export const PokemonContainer = (props: any) => {
  const [urlData, setURLData] = useState<any>([]);

  useEffect(() => {
    const get_url_data = async () => {
      setURLData((await axios.get(props.url)).data);
    };
    get_url_data();
  }, []);

  if (!urlData.id) {
    return (
      <div>
        <p>Loading...</p>
      </div>
    );
  }

  return (
    <div>
      <div key={urlData.name}>
        <p> {urlData.name}</p>
        <p> {urlData.id}</p>
        <img src={urlData.sprites.front_default}></img>
      </div>
    </div>
  );
};
  • Related