Jammming Project map function undefined?

Hi All,

Having an annoying issue with the map function for creating an array of components.

My code

import React from 'react';
import './TrackList.css';

import {Track} from '../Track/Track';

export class TrackList extends React.Component {

  listTracks() {
    console.log(this.props.listedTracks);
    return this.props.listedTracks.map(track => {
      return <Track key={track.id} title={track.title} artist={track.artist} album={track.album} />
    });
  }

  render() {
    return (
      <div className="TrackList">
        {this.listTracks()}
      </div>
    );
  }
}

keep getting the same error but the data looks fine when i console log the array?

Error message;

TypeError: Cannot read property 'map' of undefined
TrackList.listTracks
C:/Users/Steve-Laptop/OneDrive/Documents/WebSite/React/Jammming/jammming/src/components/TrackList/TrackList.js:10
   7 | 
   8 |  listTracks() {
   9 |    console.log(this.props.listedTracks);
> 10 |    return this.props.listedTracks.map(track => {
     | ^  11 |      return <Track key={track.id} title={track.title} artist={track.artist} album={track.album} />
  12 |    });
  13 |  }

log output is the expected array though?

(2) [{…}, {…}]
0: {id: "1", name: "Getting Jiggy With it", artist: "Will Smith", album: "Be Jiggy"}
1: {id: "2", name: "Lady In Red", artist: "Chris De Burgh", album: "Greatest Hits"}
length: 2
__proto__: Array(0)

Okay i posted this then realized that someone literally just posted the same problem.

I have spotted something interesting in my console log below;

[HMR] Waiting for update signal from WDS...
TrackList.js:11 {tracks: Array(2)}tracks: Array(2)0: {id: "1", name: "Getting Jiggy With it", artist: "Will Smith", album: "Be Jiggy"}1: {id: "2", name: "Lady In Red", artist: "Chris De Burgh", album: "Greatest Hits"}length: 2__proto__: Array(0)__proto__: Object
TrackList.js:11 undefined

it seems as if react is creating the component twice but the first line is shows my expected array and the second line it seems that it is now undefined which would explain my error.

Is this a react bug?

this is my edited code for the log

import React from 'react';
import './TrackList.css';

import {Track} from '../Track/Track';

export class TrackList extends React.Component {

  constructor(props) {
    super(props);

    console.log(this.props.searchResults);
  }

  render() {
    return (
      <div className="TrackList">
        <Track />
      </div>
    );
  }
}

Hi There,

Have you managed to solve this issue?

Also stuck using the ‘map’ property on the array, whereas my array does show up in the react component’s logs.

Cheers

Hi,

Its simpler than you think, look at this code

import React from 'react';
import './App.css';

import {SearchBar} from '../SearchBar/SearchBar';
import {SearchResults} from '../SearchResults/SearchResults';
import {Playlist} from '../Playlist/Playlist';

export class App extends React.Component {
  constructor(props) {
    super(props);

    //initial tracks array
    this.state = {
      searchResults:[
      {
        id:'1', 
        name:'Getting Jiggy With it', 
        artist:'Will Smith', 
        album:'Be Jiggy'
      },
      {
        id:'2', 
        name:'Lady In Red', 
        artist:'Chris De Burgh', 
        album:'Greatest Hits'
      }
    ],
    playlist:[
      {
        id:'1', 
        name:'Getting Jiggy With it', 
        artist:'Will Smith', 
        album:'Be Jiggy'
      },
      {
        id:'2', 
        name:'Lady In Red', 
        artist:'Chris De Burgh', 
        album:'Greatest Hits'
      }
    ]};
  }
  
  render() {
    return (
      <div>
        <h1>Ja<span className="highlight">mmm</span>ing</h1>
        <div className="App">
          <SearchBar />
          <div className="App-playlist">
            <SearchResults searchResults={this.state.searchResults} />
            <Playlist playlist={this.state.playlist}/>
          </div>
        </div>
      </div>    
    );
  }
}

Playlist was the issue as I hadn’t defined any properties for it and it also uses the Tracklist component, if you pass it some properties also then you may find the issue goes away.

Hope that helps!

2 Likes

Hi EveryOne,

I have the same issue And I not able to resolve because I don’t understand why executed this code multiple times?

index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './Components/App/App.js';
import * as serviceWorker from './serviceWorker';

ReactDOM.render(
	<React.StrictMode>
		<App />
	</React.StrictMode>,
	document.getElementById('root')
);

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

index.js render:

<App />
import React from 'react';
import SearchBar from "../SearchBar/SearchBar.js";
import SearchResults from "../SearchResults/SearchResults.js";
import Playlist from "../Playlist/Playlist.js";
import './App.css';

class App extends React.Component {
	constructor(props) {
		super(props);
		this.state = {
			searchResults: [
				{
					name: "1",
					artist: "1",
					album: "1",
					id: "1"
				},
				{
					name: "2",
					artist: "2",
					album: "2",
					id: "2"
				}
			],
			playlist:[
				{
					id:'1', 
					name:'Getting Jiggy With it', 
					artist:'Will Smith', 
					album:'Be Jiggy'
				},
				{
					id:'2', 
					name:'Lady In Red', 
					artist:'Chris De Burgh', 
					album:'Greatest Hits'
				}
			]
		};
	}
	render() {
		return (
			<div>
				<h1>Ja<span className="highlight">mmm</span>ing</h1>
				<div className="App">
					<SearchBar />
					<div className="App-playlist">
						<SearchResults searchResults={this.state.searchResults} />
						<Playlist />
					</div>
				</div>
			</div>
		);
	}
}

export default App;

App.js render:

<SearchBar />
import React from "react";
import "./SearchBar.css";

class SearchBar extends React.Component {
    render() {
        return (
            <div className="SearchBar">
                <input placeholder="Enter A Song, Album, or Artist" />
                <button className="SearchButton">SEARCH</button>
            </div>
        );
    }
} 

export default SearchBar;
<SearchResults />
import React from "react";
import TrackList from "../TrackList/TrackList.js";
import "./SearchResults.css";

class SearchResults extends React.Component {
    render() {
        return (
            <div className="SearchResults">
                <h2>Results</h2>
                <TrackList tracks={this.props.searchResults} />
            </div>
        );
    }
}

export default SearchResults;
<Playlist />
import React from "react";
import TrackList from "../TrackList/TrackList.js";
import "./Playlist.css";

class Playlist extends React.Component {
    render() {
        return (
            <div className="Playlist">
                <input defaultValue={'New Playlist'} />
                {/*<TrackList />*/}
                <button className="Playlist-save">SAVE TO SPOTIFY</button>
            </div>
        );
    }
}

export default Playlist;

SearchResults.js render:
(Playlist.js also render <Tracklist />; I commented out…)

<TrackList />
import React from "react";
import Track from "../Track/Track.js";
import "./TrackList.css";

class TrackList extends React.Component {
    render() {
        return (
            <div className="TrackList">
                {
                    this.props.tracks.map(track => {
                        return <Track key={track.id} track={track} />
                    })
                }
            </div>
        )
    }
}

export default TrackList;

TrackList.js render:

<Track />
import React from "react";
import "./Track.css";

class Track extends React.Component {

    renderAction() {
        return this.props.isRemoval
            ? <button className="Track-action">-</button>
        : <button className="Track-action">+</button>;
    }

    render() {
        return (
            <div className="Track">
                <div className="Track-information">
                    <h3>track name will</h3>
                    <p>track artist  |  track album</p>
                </div>
                {this.renderAction()}
            </div>
        );
    }
}

export default Track;

And how I tried to find the issue:
I modified the TrackList.js:

TrackList.js now log to the console the "this.props.tracks"
import React from "react";
import Track from "../Track/Track.js";
import "./TrackList.css";

class TrackList extends React.Component {
    render() {
        return (
            <div className="TrackList">
                {
                    console.log(this.props.tracks)
                    /*
                    this.props.tracks.map(track => {
                        return <Track key={track.id} track={track} />
                    })*/
                }
            </div>
        )
    }
}

export default TrackList;

Why log out the dataset double times?
If I delete the comment from the Playlist.js line 10: <TrackList /> then log to the console 4 times. And the third and fourth are undefined. My code crash because I try to map an undefined value instead of array.

Any idea?

Both the SearchResults Component and Playlist Component use the Tracklist component, you have passed the array as a prop called searchResults which is good for that component but you haven’t passed anything to the Playlist component!

  render() {
    return (
      <div>
        <h1>Ja<span className="highlight">mmm</span>ing</h1>
        <div className="App">
          <SearchBar />
          <div className="App-playlist">
            <SearchResults searchResults={this.state.searchResults} />
            <Playlist playlist={this.state.searchResults}/> <--- You need to add a prop to this!!!!!
          </div>
        </div>
      </div>    
    );
  }

I would say it is more that you need to pass a different prop to the playlist component rather than add a new one. I would recommend passing the prop of “tracks” to both the playlist and searchResults components and having them set to their respective arrays in the state object. That way the Tracklist component can just map through this.props.tracks for both the SearchResults and Playlist components.

1 Like