Search code examples
reactjsreact-hooksreact-dom

React map not a function


I'm currently making a presentation feature with songs included in it. I'm getting an error of listedSongs.map is not a function in this code. I am using the map function in GetSongsRequest to add the songs into a div. This is working fine.

The thing that is failing is the map function in SongsInList and I'm not quite sure why because the map functions are almost identical except I have had to raise the state of listedSongs so it is accessible to both functions.

import React, {useState, useEffect} from "react"
import { useAuth0 } from "@auth0/auth0-react";

function GetSongsRequest(listedSongs, addListedSongs) {
    const { user } = useAuth0();
    const [songs, setSongs] = useState([])

    useEffect(() => {
        if (user) {
            const requestOptions = {
                method: 'GET'
            };
            let url = '#' + user.sub
            fetch(url, requestOptions)
            .then(response => {
                return response.json();
            }).then(jsonResponse => {
                setSongs(jsonResponse)
                localStorage.setItem('songsStorage', JSON.stringify(jsonResponse))
            }).catch (error => {
                console.log(error);
            }) 
        }
    }, [user])
    return (
        <>
        <ul>
            {songs.map((el) => (
                <li key={el} className="tailwindCssStuff"
                onClick={ () => addListedSongs(listedSongs.concat(el)) }>
                {el[0]}</li>
            ))}
        </ul>
        </>
    )
}

function SongsInList(listedSongs) {
    return (
            <ul>
                {listedSongs.map((el) => (
                <li key={el} className="tailwindCssStuff">
                {el[0]}</li>
                ))}
            </ul>
    )
}

export default function Main() {
    const [listedSongs, addListedSongs] = useState([])
    return (
    <div>
        <div id="userContent" className="tailwindCssStuff">
            <h1 className="tailwindCssStuff">Songs</h1>
            <div id = "vertical-content">
                <GetSongsRequest listedSongs={listedSongs} addListedSongs={addListedSongs} />
            </div>
        </div>
        <div id="liveList" className="tailwindCssStuff">
            <h1 className="tailwindCssStuff">List</h1>
            <div id = "vertical-list">
                <SongsInList listedSongs={listedSongs} />
            </div>
        </div>
    </div>
    )
}
  • Example Data:
[["Song","LINE 1\nLINE 2\nLINE 3\nLINE 4"],["Song 2","LINE 1\nLINE 2\nLINE 3\nLINE 4"],["Song 3","LINE 1\nLINE 2\nLINE 3\nLINE 4"],["Song 4","LINE 1\nLINE 2\nLINE 3\nLINE 4"],["Song 5","LINE 1\nLINE 2\nLINE 3\nLINE 4"],["SONG 6","SEDTRFGYUHIJ\nRXDGYUIHJO\nRDFTGYUHIJOKP\nJRCFGVHBJN"]]

This is an example of what I would get from the GET request

Thanks!


Solution

  • Assuming the data fetching at state updates are correct, you've a few issues with props handling.

    GetSongsRequest needs to access the props correctly. Resolve this by destructuring from the props object.

    import React, { useState, useEffect } from "react";
    import { useAuth0 } from "@auth0/auth0-react";
    
    function GetSongsRequest({ listedSongs, addListedSongs }) {
      const { user } = useAuth0();
      const [songs, setSongs] = useState([])
    
      useEffect(() => {
        if (user) {
          const requestOptions = {
            method: 'GET'
          };
          let url = '#' + user.sub
          fetch(url, requestOptions)
            .then(response => {
              return response.json();
            }).then(jsonResponse => {
              setSongs(jsonResponse)
              localStorage.setItem('songsStorage', JSON.stringify(jsonResponse))
            }).catch (error => {
              console.log(error);
            }) 
        }
      }, [user])
      return (
        <ul>
          {songs.map((el) => (
            <li key={el} className="tailwindCssStuff"
              onClick={ () => addListedSongs(listedSongs.concat(el)) }>
              {el[0]}</li>
          ))}
        </ul>
      )
    }
    

    Similarly, SongsInList needs to destructure the listedSongs props which is the array you want to map.

    function SongsInList({ listedSongs }) {
      return (
        <ul>
          {listedSongs.map((el) => (
            <li key={el} className="tailwindCssStuff">
              {el[0]}
            </li>
          ))}
        </ul>
      )
    }
    

    Main is ok.

    export default function Main() {
      const [listedSongs, addListedSongs] = useState([])
      return (
        <div>
          <div id="userContent" className="tailwindCssStuff">
            <h1 className="tailwindCssStuff">Songs</h1>
            <div id = "vertical-content">
              <GetSongsRequest listedSongs={listedSongs} addListedSongs={addListedSongs} />
            </div>
          </div>
          <div id="liveList" className="tailwindCssStuff">
            <h1 className="tailwindCssStuff">List</h1>
            <div id = "vertical-list">
              <SongsInList listedSongs={listedSongs} />
            </div>
          </div>
        </div>
      )
    }