I completed this project earlier this week and ran into my fair share of issues trying to get it to work. Given how frustrating some of these issues were, I thought I would share some of what I learned while working on this so that people running into the same problems have another resource to look into.
Step 11:
Since we used ‘create-react-app’ to generate the initial app template, the App component will be created as a function rather than a class extension and will not contain a render method. My fix was to re-write it as a class extension.
Step 34:
TypeError: Cannot read property ‘map’ of undefined
The undefined in this error message is the this.props.tracks
array which is supposed to be passed in from SearchResults. I honestly don’t know what causes this issue; my assumption is that there is some sort of asynchronous process taking place in the background when we’re passing the state from App through SearchResults as props and finally to TrackList. The error is due to the props received by TrackList being undefined. The way I resolved it was by wrapping the return statement in TrackList’s render method within an if
statement, a solution I found here after googling the error message.
What it appears to do is allow React to not break on the missing props in TrackList by not rendering while it’s still undefined, and then render when props finally receive its value from SearchResults.
Here’s my render method in TrackList:
Render
render() {
if (this.props.tracks) {
return (
<div className="TrackList">
{this.props.tracks.map(track => <Track key={track.id} track={track} />)}
</div>
)
} else {
return null;
}
}
The alternative is to comment out the Playlist component until Step 39 where it gets the props needed to make it function correctly. When I got to step 39, I removed the if
block wrapping, and everything worked fine.
Step 73:
A step to bind the this.search
event handler to the ‘Search’ button appears to have been left out. It’s possible I simply missed it somehow, but after doing a search for onClick events in the instructions, I only found 3 of them (add-track, remove-track, save-to-spotify).
I made the following change to the button element in SearchBar.js:
<button className="SearchButton" onClick={this.search}>SEARCH</button>
From Step 79 on, you enter hard-mode – there is a big ramp-up in things that you’ll need to brush up on or research. I found it useful to review the asynchronous lessons covering promises and fetch as these technologies are how we’ll be interacting with the Spotify API. We’ll also be using properties and methods of the window object (basically your browser), so I also found it useful to look over its documentation. Regardless, reviewing the hints becomes pretty necessary in this part, and I often reviewed the help-video after I tried to complete a step to see what the end results were supposed to look like as I didn’t want to propagate an error further down that would make troubleshooting much harder.
Step 79:
Match is a string method, and you need to make sure you understand how it works. For one thing, it returns an array, not just a string that matched your regex which was my assumption. Second, it can return more than one match (which would be contained in the array). You’ll need to figure which of the matches within the array you need.
Step 81:
Note that http://localhost:3000/
and http://localhost:3000
are NOT the same. If you add a slash at the end, make sure you have it in both Spotify.js
and your Spotify dashboard.
Step 83:
More of an FYI – the redirect URL sends the user to Spotify to login and grant permission to the app to save a playlist to their account. While the answer is in the question, I was trying to see if I can complete this step by only using the Spotify documentation, and built the URL by hand and only put in the required parameters. It turns out the scope parameter is what Spotify uses to determine what your app can do and leaving it out will generate an error that you need to catch in the console.
Step 84:
So don’t make the mistake that I made here – DON’T USE the tracks endpoint guide, DO USE the search endpoint guide.
Step 90 - 94:
Over the course of writing the savePlaylist
method, three fetch requests will be made. The first will be an authentication request using the access token you will obtain by using the getAccessToken
method written earlier, the second will be a request to create a new playlist in the user’s account, and the third will be to populate that playlist with tracks.
Here’s something to keep in mind – fetch is asynchronous. This means by default, you don’t know the order in which your fetch requests will be resolved. This is a problem for this method as there are dependencies – you won’t be able to create a playlist without being authenticated, and you can’t add tracks to a playlist that hasn’t been created yet. You will need to nest these requests together in such a way that the next one doesn’t kick-off until its predecessor has successfully resolved.
That’s it for now, here’s hoping this write-up helps save some hair-pulling and/or monitors from blunt-force trauma.