0

I'm using Axios to get a DeezerAPI, so fist of all I render info using an .map() and everything was fine when accessing information and passing it to a Component, but when I try to access a single JSON object I get an 'undefined' error.

Sample of Axios request React.js

//State with Redux
//No problem with Redux
const apiData = useSelector((state) => state.data);

//Local State to store fetched data from API
const [Songs, setSongs] = useState([]);

//AXIOS everything is fine here
useEffect(() => {
    const getFetchData = async () => {
      try {
        const res = await axios.request({
          method: "GET",
          url: "https://deezerdevs-deezer.p.rapidapi.com/search",
          params: { q: apiData }, //apiData is for searching an artist, song...
          headers: {
            "X-RapidAPI-Host": "deezerdevs-deezer.p.rapidapi.com",
            "X-RapidAPI-Key": "randomNumbersKey",
          },
        });
        const data = res.data.data;
        setSongs(data); //stored in state
      } catch (error) {
        console.log(error);
      }
    };
    getFetchData();
  }, [apiData]); 

Example data from API

So when I try to access a single JSON object using a console.log() as the following example

console.log(Songs[0].title)

I get an error saying this:

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

I still don't know why this happen when selecting a single object, if I use a .map() I won't have any problem.

Thanks in advance for any help :D

  • Idiomatic JavaScript + React reserves variable names starting with a capital letter for classes, constructor functions, and components. You shouldn't use that naming convention for other things, such as arrays. – Quentin Apr 16 '22 at 23:53

2 Answers2

0

The initial value of the state is [].

So you can map over it (and get an empty array back) but if you try to access Songs[0] you will get undefined and accessing a property of it will throw an error.

After the initial render, the effect hook will run and (a little later) the Ajax response will come in and update the value in the states (presumably with an array that isn't empty).

Until then you can't access the non-existent first element of the array.

You could test for it and act conditionally:

if (Songs[0]) {
    // something with Songs[0].title
} else {
    // Something else
} 
Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
0

It looks like you have a classic asynchronous programming issue. Both your fetch a d setState are run asynchronously, which means the render function continues to execute, and does not wait for the fetch to finish. So at the time you access the results in your render Songs is an empty array. In JS indexing outside array bounds returns undefined, instead of throwing, hence the error you're seeing.

When writing a React component you must always handle the situation where effects have not yet run and your state is in it's default state. Using map in your case handles this, because mapping over an empty array yields an empty array, which react doesn't render. Another option is to check if you are in your intial state and return null. This will keep react from rendering anything to the DOM until the state is updated.

In general in React, don't assume you know the value of state at any given time. Instead handle each different possible state

Nick Bailey
  • 3,078
  • 2
  • 11
  • 13