Jammming - Cannot read properties of undefined (reading 'map')


Hi,

Can someone help me with this issue please? My code is below. Cheers.

TrackList.js

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



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

    }

    )

	};
	</div>
	)

	};
};

@ruby1026833317, do you have your code for your Playlist component? You could have a syntax error when passing the track props from Playlist into TrackList.

Hi mate,

Here’s my Playlist.js file below. Thanks!

Playlist.js

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


class Playlist extends React.Component {
constructor(props){
super(props); 
this.handleNameChange = this.handleNameChange.bind(this);

};

handleNameChange(event) {
	this.props.onNameChange(event.target.value);

}
	render() {
		return(

<div className="Playlist">
  <input defaultValue={"New Playlist"} onChange={this.handleNameChange} />
  <button className="Playlist-save" onClick={this.props.onSave}>SAVE TO SPOTIFY</button>
</div>


)
	}
};

The error you are getting is from the map function not being able to find any values for your ‘tracks’ prop in TrackList.js. You’ve imported Tracklist.js into Playlist.js, but you need to add it as a component and pass in the ‘tracks’ prop in the body of your code. Your code should look like this:

Playlist.js

import React from "react";
import "./Playlist.css";
import TrackList from "../TrackList/TrackList";

class Playlist extends React.Component {
	constructor(props) {
		super(props);
		this.handleNameChange = this.handleNameChange.bind(this);
	}

	handleNameChange(event) {
		this.props.onNameChange(event.target.value);
	}

	render() {
		return (
			<div className="Playlist">
				<input defaultValue={"New Playlist"} onChange={this.handleNameChange} />
				<TrackList
					tracks={this.props.playlistTracks}
					onRemove={this.props.onRemove}
					isRemoval={true}
				/>
				<button className="Playlist-save" onClick={this.props.onSave}>
					SAVE TO SPOTIFY!
				</button>
			</div>
		);
	}
}

This is the part you need to add to your code:

		<TrackList
			tracks={this.props.playlistTracks}
			onRemove={this.props.onRemove}
			isRemoval={true}
		/>

TrackList.js

import React from "react";
import "./TrackList.css";
import Track from "../Track/Track";

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

export default TrackList;

Hope that solves it! If you run into any more issues let me know :slight_smile:

Hi mate,

I’m still receivng exactly the same issue of ‘map is undefined’. Do you know why that could be sorry? Cheers

Ah bummer. If you send me all your code for the project, I’ll have a look at it for you. You can either upload it to GitHub or post everything here.

App.js

import React from 'react';
import './App.css';
import SearchBar from '../SearchBar/SearchBar';
import SearchResults from '../SearchResults/SearchResults';
import Playlist from '../Playlist/Playlist';
import TrackList from '../TrackList/TrackList';

class App extends React.Component {
  constructor(props){
    super(props);
    this.state = {
      SearchResults: [{ name: 'name1', artist: 'artist1', album: 'album1', id: 1}, 
      {name: 'name2', artist: 'artist2', album: 'album2', id: 2}, {name: 'name3', artist: 'artist3', album: 'album3', id: 3}],
      playlistName: 'Ma 15th bday',
      playlistTracks: [{ name: 'playlistName1', artist: 'playlistArtist1', album: 'playlistAlbum1', id: 4}, {name: 'playlistName2', artist: 'playlistArtist2', album: 'playlistAlbum2', id: 5}, {name: 'playlistName3', artist: 'playlistArtist3', album: 'playlistAlbum3', id: 6}]  
    }
    this.addTrack = this.addTrack.bind(this);
    this.removeTrack = this.removeTrack.bind(this);
    this.updatePlaylistName = this.updatePlaylistName.bind(this);
    this.savePlaylist = this.savePlaylist.bind(this);
    this.search = this.search.bind(this);
  }
addTrack(track){
  let tracks = this.state.playlistTracks;
  if (tracks.find(savedTrack => savedTrack.id === track.id)) {
    return;
  }

  tracks.push(track);
  this.setState({ playlistTracks: tracks });
}

removeTrack(track){
  let tracks = this.state.playlistTracks;
  tracks = tracks.filter(currentTrack => currentTrack.id !== track.id) 
 this.setState({ playlistTracks: tracks });
  }

  updatePlaylistName(name){
    this.setState({ playlistName: name });
  }

  savePlaylist(){
    let trackUris = this.state.playlistTracks.map(track => track.uri); 
  }

  search(term){
  console.log(term);
  
  }

render() {
    return (
    <div>
  <h1>Ja<span className="highlight">mmm</span>ing</h1>
  <div className="App">
    <SearchBar onSearch={this.search} />
    <div className="App-playlist">
      <SearchResults searchResults={this.state.searchResults} onAdd={this.addTrack}
       />
      <Playlist playlistName={this.state.playlistName} playlistTracks={this.state.playlistTracks} onNameChange={this.state.updatePlaylistName} onSave={this.savePlaylist} />
    </div>
  </div>
</div>
    )
  }
}


export default App;

Playlist.js

import React from "react";
import "./Playlist.css";
import TrackList from "../TrackList/TrackList";

class Playlist extends React.Component {
	constructor(props) {
		super(props);
		this.handleNameChange = this.handleNameChange.bind(this);
	}

	handleNameChange(event) {
		this.props.onNameChange(event.target.value);
	}

	render() {
		return (
			<div className="Playlist">
				<input defaultValue={"New Playlist"} onChange={this.handleNameChange} />
				<TrackList
					tracks={this.props.playlistTracks}
					onRemove={this.props.onRemove}
					isRemoval={true}
				/>
				<button className="Playlist-save" onClick={this.props.onSave}>
					SAVE TO SPOTIFY!
				</button>
			</div>
		);
	}
};

export default Playlist;

SearchBar.js

import React from 'react';

import './SearchBar.css';


class SearchBar extends React.Component {
	constructor(props){
		super(props);
		
		this.state = {
         
         term: ''

		}
		this.search = this.search.bind(this);
		this.handleTermChange = this.handleTermChange.bind(this);
	}

search(){
	this.props.onSearch(this.state.term);
}

handleTermChange(event){
	this.setState({ term: event.target.value });
}

	render() {
		return (
<div className="SearchBar">
  <input placeholder="Enter A Song, Album, or Artist" onChange={this.handleTermChange} />
  <button className="SearchButton">SEARCH</button>
</div>


		)
	}
}


export default SearchBar;

SearchResults.js

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

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



export default SearchResults;

Track.js

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

class Track extends React.Component {
	constructor(props){
		super(props);
		this.addTrack = this.addTrack.bind(this);
		this.removeTrack =this.removeTrack.bind(this);
	}

renderAction() {
	if(this.props.isRemoval) {
		return <button className="Track-action" onClick={this.removeTrack}>-</button>
	} else {
       return <button className="Track-action" onClick={this.addTrack}>+</button>
	}

}

addTrack() {
	this.props.onAdd(this.props.track); 
}

removeTrack() {
	this.props.onRemove(this.props.track);
}

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

	)
	}
};


export default Track;

TrackList.js


import React from "react";
import "./TrackList.css";
import Track from "../Track/Track";

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

export default TrackList;

@ruby1026833317

In app.js it looks like you’ve defined your search results as ‘SearchResults’ (with a capital S) but passed it down to your Search Results component as ‘searchResults’ (with a little s). This is causing a knock-on effect to your map in your Tracklist component as it can’t any values to map.

class App extends React.Component {
  constructor(props){
    super(props);
    this.state = {
      SearchResults: [{ name: 'name1', artist: 'artist1', album: 'album1', id: 1}, 
      {name: 'name2', artist: 'artist2', album: 'album2', id: 2}, {name: 'name3', artist: 'artist3', album: 'album3', id: 3}],
      playlistName: 'Ma 15th bday',
      playlistTracks: [{ name: 'playlistName1', artist: 'playlistArtist1', album: 'playlistAlbum1', id: 4}, {name: 'playlistName2', artist: 'playlistArtist2', album: 'playlistAlbum2', id: 5}, {name: 'playlistName3', artist: 'playlistArtist3', album: 'playlistAlbum3', id: 6}]  
    }

//rest of code....

return (
    <div>
  <h1>Ja<span className="highlight">mmm</span>ing</h1>
  <div className="App">
    <SearchBar onSearch={this.search} />
    <div className="App-playlist">
      <SearchResults searchResults={this.state.searchResults} onAdd={this.addTrack}
       />
      <Playlist playlistName={this.state.playlistName} playlistTracks={this.state.playlistTracks} onNameChange={this.state.updatePlaylistName} onSave={this.savePlaylist} />
    </div>
  </div>
</div>
    )

//rest of code....

The best practice is to name everything in ‘camelCase’ unless it is a component which needs to be in ‘TitleCase’. If you update the following then it should work:

In App.js from this:

   this.state = {
      SearchResults: [{ name: 'name1', artist: 'artist1', album: 'album1', id: 1}, 
     //rest of code...
    }

to this:

   this.state = {
      searchResults: [{ name: 'name1', artist: 'artist1', album: 'album1', id: 1}, 
     //rest of code...
    }

and in SearchResults.js from this:

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

to this:

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

it should work :crossed_fingers:

Hope that helps!

2 Likes

Hi Henry,

First of all, very sorry for the late response, as I’m very busy with work currently. Also, I really appreciate the help mate, thanks.

However, while the searchResults has alleviated some errors, I’m still getting the same error message I had to begin with, of 'cannot read properties of undefined (reading ‘map’) '.

Sorry to be a pain, but I just can’t see the issue. Cheers.

No worries buddy, are you able to commit all your code to GitHub and I’ll have a look at it for you?