Noah Dennis
Noah Dennis

Reputation: 92

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>
    )
}
[["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!

Upvotes: 1

Views: 1198

Answers (2)

Carlos Cruz
Carlos Cruz

Reputation: 17

The issue here is the way you are reading props for the GetSongsRequest and SongsInList components.

Functional components do get the props as the first parameter (check react docs)

You can use:

function SongsInList(props) {
    return <ul>
        { props.listedSongs.map( ... ) }
    </ul>
}

Or either make an object destruction in the function parameters:

function SongsInList({ listedSongs }) {
    return ...
}

function GetSongsRequest({ listedSongs, addListedSongs }) {
    return ...
}

Upvotes: 0

Drew Reese
Drew Reese

Reputation: 202836

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>
  )
}

Upvotes: 2

Related Questions