"Jamming" React project, implement a react-spinner npm while savePlaylist() is saving to Spotify API

Hello all,

This is my first “asking for help” post on codeacademy, so please forgive me if I’m not fully up to speed with the posting guidelines.

Context: I have completed the “Jamming” project in the “React part 2” section, which has brought me onto the “feature request” task which immediately follows. Based on the codeacademy suggestions I opted to do the "loading-spinner while savePlaylist() method saves to Spotify through the API.

I have successfully implemented the loading-spinner by merely altering the state manually, but I can’t get the feature to work when I try and implement it properly with the onClick={this.props.onSave} which goes through to the API.

The only two files I believe I need to alter to implement this are:

App.js (parent) - codepenlink: https://codepen.io/GCW047/pen/QWMgLVW
Playlist.js (child) - codepenlink: https://codepen.io/GCW047/pen/dyzRbwe

I have tried to remove any code that isn’t related to the subject at hand while still giving people a chance to follow what I have tried to do, but full code is attached in links to codepen above if this is prefferred.

As per the nature of the project I am not using function components, I am using methods within the class components, with state being contained within the constructor / super.

Problem: The playlist is saved to spotify through the API, but the loader-spinner does not manifest while this is being carried out, it just appears blank as it does when the playlist is submitted normally. The Playlist save is successful.

Within parent element “App,js” the savePlaylist() method is called from child component “Playlist.js” when a button is clicked and the "onClick={this.props.onSave} attribute is involked.

This should change the “loading” state in app.js to true, which should then be fed down into the child component though delegateStatusToChild={this.state.loading}, which should then activate the loading-spinner by way of the ternary operator. This should then stop once the .then statement promise returns a response from the API.

App.js code

savePlaylist() { this.setState({loading: true}); const trackUris = this.state.playlistTracks.map(track => track.uri); setTimeout(() => { Spotify.savePlayList(this.state.playlistName, trackUris).then(() => { this.setState({ playlistName: "New Playlist", playlistTracks: [], loading: false }) }) }, 4000) } 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} onRemove={this.removeTrack} onNameChange={this.updatePlaylistName} onSave={this.savePlaylist} delegateStatusToChild={this.state.loading} /> </div> </div> </div> ) } } export default App;

Playlist.js code

import React from 'react'; import "./Playlist.css" class Playlist extends React.Component { constructor(props) { super(props); this.handleNameChange = this.handleNameChange.bind(this); this.state = { loading: this.props.delegateStatusToChild }; } render() { return ( <div className="Playlist"> { this.state.loading ? <PacmanLoader color={"rgb(255,255,255)"} loading={this.props.loading} size={50} /> : <div> <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> } </div> ) } } export default Playlist;

I am really sorry for writing war a peace, hopefully someone doesn’t get bored of reading and can help me determine where I have gone wrong. I believe the state is not being communicated to the child to activate the ternary operator properly, but I have done simple tests for this by changing the state manually.

Any help would be massively appreciated.

https://www.codecademy.com/paths/full-stack-engineer-career-path/tracks/fscp-react-part-ii/modules/fecp-challenge-project-jammming/projects/jammming-prj - this is the original jamming task within CA.

I’m not sure if that is the cause of the issue as I’m more familiar with function components, but what seems a little odd to me is that you save the loading state as state twice: In the constructor of App.js as well as in the constructor of Playlist.js.
I think it should be saved to the state of App.js – where you update the state – only and then be passed down to the Playlist component where it is read by the ternary operator directly.

Hi mirja_t,

Thank you for you quick reply on this one. Your solution to only pass the state down to be read directly by the ternary operator seems to have worked! We have now got the loading-spinner appearing while the API request is completed.

As you will have known from your solution, where I was going wrong was that I was of the belief that I had to capture the passed down props state within the child component constructor in order for it to be utilised in its contained methods.

While we are on the subject I was wondering if you might be able to answer another query. Seen as the “functional components” seem to do everything that Class components do, is there any need at all to use class components? Do they more or less replace class components in React? or am I missing something? My searches into the subject haven’t found anything.

Again, thanks for your help

1 Like

Not that I know of. I would rather say there are things you can do with function components but not with class components. The reason the Spotify project is class based is that the course has been developed before Facebook delivered function components as far as I know. Codecademy has an update on function components later in the Frontend path. Yet I don’t think you’re wasting your time with class components as the core concepts are the same and you’ll still see sample code online that’s been written class based and it is useful to be able to read that, too.

Thanks, that all makes sense in terms of when the course was developed, and definitely always good to be able to do it both ways should you encounter one method or the other at some point.