Home > front end >  React map not a function
React map not a function

Time:11-21

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!

CodePudding user response:

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

CodePudding user response:

In my opinion you're not saving the array in the state. Please check the response before saving it to the state. Because if it's not array data-type, map will not work here.

CodePudding user response:

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

  • Related