Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Why am I getting Object are not valid as a React child

I am using a Spotify API to fetch songs and I am trying to display the first song for testing.

I am trying to display the first song as text but currently I am getting the error
"Objects are not valid as a React child (found: Object with keys {_U, _V, _W, _X}). If you meant to render a collection of children use a array instead.

I am confused as I am just trying to the first thing from the JSON and display it as a text on the stats screen

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

import React, {useState} from "react";
import axios from "axios";
import { getSpotifyToken } from "../../hooks/spotifyAuth";

const getTopTracks = async () => {
  //Getting spotify token
  const spotifyToken = getSpotifyToken();
  console.log("Getting access Token for TopSongs:", spotifyToken );

  // const [songName, setSongName] = useState("");

  const api_url = "https://api.spotify.com/v1/me/top/tracks?time_range=short_term&limit=5";
  // const api_url = "https://api.spotify.com/v1/me/top/artists?time_range=short_term&limit=1&offset=5";
  
  // console.log(api_url);
  try{
    const response = await axios.get(api_url, {
      headers: {
        'Authorization': `Bearer ${spotifyToken}`
      }
    });

    const myJSON = response.data.items[0].name.toString();
    console.log("My JSON:", myJSON); //this just prints the song name
    return myJSON;
  }catch(error){
    console.log(error);
  }  
};

const StatsScreen = ({ navigation }) => {
  const topSong = getTopTracks();


  return (
    <View>
      <Text>StatsScreen</Text>
      <Text>{topSong}</Text>
    </View>
  );
};

export default StatsScreen;

>Solution :

Because topSong is a promise, not a string. async functions always return promises (more here).

If you want StatsScreen to retrieve the top song, you’ll need to make it stateful, since initially it won’t have a song to show:

const StatsScreen = ({ navigation }) => {
    const [topSong, setTopSong] = useState(null);
    useEffect(() => {
        getTopSongs()
        .then(setTopSong)
        .catch((error) => {
            // ...handle/report error...
        })
    }, []); // <== Empty deps array = only on mount

    return (
        <View>
            <Text>StatsScreen</Text>
            {topSong && <Text>{topSong}</Text>}
        </View>
    );
};

That fetches the top song on mount via useEffect, and stores the result as state using useState. I’ve had it not render the second Text at all when it doesn’t have one, but of course you can tweak that as desired, for instance:

    return (
        <View>
            <Text>StatsScreen</Text>
            <Text>{topSong ? topSong : "Loading top song..."}</Text>
        </View>
    );
};

A more robust version can use an AbortController (in axios v0.22.0 and up; for earlier versions, use the deprecated axios-specific CancelToken) to cancel the outstanding HTTP request if the component is unmounted while it’s running:

const getTopTracks = async (signal) => {
    //                      ^^^^^^ <====
    // ...
    try {
        const response = await axios.get(api_url, {
            signal, // <====
            headers: {
                Authorization: `Bearer ${spotifyToken}`,
            },
        });
        // ...
    } catch (error) {
        console.log(error);
    }
};

const StatsScreen = ({ navigation }) => {
    const [topSong, setTopSong] = useState(null);
    useEffect(() => {
        const controller = new AbortController();   // <====
        getTopSongs(controller.signal)              // <====
            .then(setTopSong)
            .catch((error) => {
                // ...handle/report error...
            });
        return () => {                              // <====
            // Called on unmount                    // <====
            controller.abort();                     // <====
        };
    }, []); // <== Empty deps array = only on mount

    return (
        <View>
            <Text>StatsScreen</Text>
            {topSong && <Text>{topSong}</Text>}
        </View>
    );
};
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading