0

I'm building a prototype that fetches a Spotify user's playlist data in React. The data fetching is done inside a useEffect hook and sets the state of playlists variable. Consequently, I want to render the name of each playlist. However, it seems that the data is only fetched after rendering, causing an issue, because the state is not set before rendering, so playlists variable is undefined. How can I solve this problem while continuing to use React hooks? My code is below.

import './App.css'
import queryString from 'query-string'
import React, { useState, useEffect } from 'react'

const App = () => {

  const [userData, setUserData] = useState({})
  const [accesstoken, setAccesstoken] = useState('')
  const [playlists, setPlaylists] = useState({})

  useEffect(() => {

    let parsed = queryString.parse(window.location.search)
    let accesstoken = parsed.access_token
    if (!accesstoken) {
      return
    }
    setAccesstoken(accesstoken)

    fetch('https://api.spotify.com/v1/me', {
      headers: {'Authorization': 'Bearer ' + accesstoken}
    }).then(response => response.json())
    .then(data => setUserData(data))

    fetch(`https://api.spotify.com/v1/me/playlists`, {
      headers: {'Authorization': 'Bearer ' + accesstoken}
    }).then(response => response.json())
    .then(data => setPlaylists(data))

  }, [])

  return(
    <div>
      {accesstoken ? (
        <div>
          <h1>Welcome, {userData.display_name}</h1>
          <h2>Playlists</h2>
          <div>
            {playlists.items.map(playlist => 
              <p>
                {playlist.name}
              </p>
            )}
          </div>
        </div>
      ) : (
        <button onClick={() => window.location = 'http://localhost:8888/login'}>Login</button>
      )}
    </div>
  );
}

export default App;

2 Answers 2

0

Use conditional rendering. Check for values in render

   <div>
      {userData && <h1>Welcome, {userData.display_name}</h1>}
      <h2>Playlists</h2>
      {playlists && playlists.items && (
        <div>
          {playlists.items.map((playlist) => (
            <p>{playlist.name}</p>
          ))}
        </div>
      )}
    </div>;
Sign up to request clarification or add additional context in comments.

Comments

0

You can add a check. see below {playlists && playlists?

import './App.css'
import queryString from 'query-string'
import React, { useState, useEffect } from 'react'

const App = () => {

  const [userData, setUserData] = useState({})
  const [accesstoken, setAccesstoken] = useState('')
  const [playlists, setPlaylists] = useState({})

  useEffect(() => {

    let parsed = queryString.parse(window.location.search)
    let accesstoken = parsed.access_token
    if (!accesstoken) {
      return
    }
    setAccesstoken(accesstoken)

    fetch('https://api.spotify.com/v1/me', {
      headers: {'Authorization': 'Bearer ' + accesstoken}
    }).then(response => response.json())
    .then(data => setUserData(data))

    fetch(`https://api.spotify.com/v1/me/playlists`, {
      headers: {'Authorization': 'Bearer ' + accesstoken}
    }).then(response => response.json())
    .then(data => setPlaylists(data))

  }, [])

  return(
    <div>
      {accesstoken ? (
        <div>
          <h1>Welcome, {userData.display_name}</h1>
          <h2>Playlists</h2>
          <div>
            {playlists && playlists?.items.map(playlist => 
              <p>
                {playlist.name}
              </p>
            )}
          </div>
        </div>
      ) : (
        <button onClick={() => window.location = 'http://localhost:8888/login'}>Login</button>
      )}
    </div>
  );
}

export default App;

3 Comments

That doesn't seem to work... What does that do exactly? I assume it checks if playlists is defined but not sure haha.
It checks if the playlist is not undefined and the playlist has the item. are you seeing a blank screen? I see you have a return statement if the access token is blank. are you sure, you have authentication in place?
It does work like this: playlists && playlists.items && ( <div> {playlists.items.map(playlist => ( <p key={playlist.id}>{playlist.name}</p> ))} </div> )}

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.