I am working with React and I have a button that is suppose to set a state
<button class="button" onClick={this.setRecommendations}>
Log Into Spotify
</button>
This calls the fucntion
setRecommendations(){
recommendations().then(recs => {
this.setState({recommendations: recs});
});
}
which updates this state recommendations: [],
so when I click the button I wait a while, and nothing happens, but sure enough no matter how long I wait the moment I click the button again, results begin to display.
I know that setState is async but this code mimics an similar function that displayed results more instantaneously with just one click, is there anything I can do to make it work with one click?
*******update with more code*******
This is my app
class App extends React.Component {
//constructor
constructor(props) {
super(props);
this.state = {
searchResults: [],
recommendations: [],
playlistName: 'New Playlist',
playlistTracks: [],
topAlbums: ["Cats", "Wicked", "Heathers", "Charli", "Little Mermaind"],
album_count: [10, 20, 25, 30, 35],
topArtist: ["Dua Lipa", "Sierra Boggess", "Barrett Wilbert Reed", "Charli XCX", "Jessica Klean"],
artist_count: [5, 10, 25, 35, 55],
topGenre: ["classical", "broadway", "pop", "punk", "hip-hop"],
genre_count: [50, 25, 5, 13, 7],
popRange: ["0-20", "21-40", "41-60", "61-80", "81-100"],
pop_count: [20, 40, 60, 40, 20]
};
this.search = this.search.bind(this);
this.setRecommendations = this.setRecommendations.bind(this);
this.addTrack = this.addTrack.bind(this);
this.removeTrack = this.removeTrack.bind(this);
this.updatePlaylistName = this.updatePlaylistName.bind(this);
this.savePlaylist = this.savePlaylist.bind(this);
}
search(term) {
Spotify.search(term).then(searchResults => {
this.setState({searchResults: searchResults});
});
}
setRecommendations(){
recommendations().then(recs => {
this.setState({recommendations: recs});
});
}
//addTracks
addTrack(track) {
let tracks = this.state.playlistTracks;
if (tracks.find(savedTrack => savedTrack.id === track.id)) {
return;
}
tracks.push(track);
this.setState({playlistTracks: tracks});
}
//removeTracks
removeTrack(track) {
let tracks = this.state.playlistTracks;
tracks = tracks.filter(currentTrack => currentTrack.id !== track.id);
this.setState({playlistTracks: tracks});
}
//updatePlaylistName
updatePlaylistName(name) {
this.setState({playlistName: name});
}
//savePlaylist
savePlaylist() {
const trackUris = this.state.playlistTracks.map(track => track.uri);
Spotify.savePlaylist(this.state.playlistName, trackUris).then(() => {
this.setState({
playlistName: 'New Playlist',
playlistTracks: []
});
});
}
//This what we will see
render() {
//this.recommendations()
return (
<div>
<h1>Spotify Recommendations</h1>
<div className="App">
<button class="button" onClick={this.setRecommendations}>
Log Into Spotify
</button>
<Graphs data={this.state.album_count} margin={this.state.topAlbums} />
<div className="Graphs">
<Graphs data={this.state.artist_count} margin={this.state.topArtist} />
</div>
<p> below are some recommendations based on your listening history </p>
<div className="App-playlist">
<RecommendationResults recommendationResults={this.state.recommendations}
onAdd={this.addTrack} />
<Playlist playlistName={this.state.playlistName}
playlistTracks={this.state.playlistTracks}
onNameChange={this.updatePlaylistName}
onRemove={this.removeTrack}
onSave={this.savePlaylist} />
</div>
</div>
</div>
);
}
}
After clicking the button it displays recommendations
<RecommendationResults recommendationResults={this.state.recommendations}
onAdd={this.addTrack} />
which calls this component
class RecommendationResults extends React.Component {
render() {
return (
<div className="RecommendationResults">
<h2>Recommendations</h2>
<TrackList tracks={this.props.recommendationResults} onAdd={this.props.onAdd} />
</div>
);
}
}
Which calls another component
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}
isRemoval={this.props.isRemoval}
onRemove={this.props.onRemove} />
})
}
</div>
);
}
}
This is the function setRecommendations calls
//get recommendations based off song history
export async function recommendations(){
const unique = await findUnique();
const recommendations = [];
for(var index = 0; index < unique.length; index++){
var trackURI = (unique[index].uri).slice(14, (unique[index].uri).length);
var rec = await Spotify.recommendations(trackURI, unique[index].pop);
for(var i=0; i<rec.length; i++){
recommendations.push(rec[i]);
}
}
const uniqueRec = getUnique(recommendations);
return await uniqueRec;
}
This function is the issue, nothing is returned from the else clause, thus if it is the first time it is called nothing will be returned until the second time.
//getAccessToken
getAccessToken() {
if (accessToken) {
return accessToken;
}
const accessTokenMatch = window.location.href.match(/access_token=([^&]*)/);
const expiresInMatch = window.location.href.match(/expires_in=([^&]*)/);
if (accessTokenMatch && expiresInMatch) {
accessToken = accessTokenMatch[1];
const expiresIn = Number(expiresInMatch[1]);
window.setTimeout(() => accessToken = '', expiresIn * 1000);
window.history.pushState('Access Token', null, '/'); // This clears the parameters, allowing us to grab a new access token when it expires.
return accessToken;
} else {
const accessUrl = `https://accounts.spotify.com/authorize?client_id=${clientId}&response_type=token&scope=${scopes.join("%20")}&redirect_uri=${redirectUri}`;
window.location = accessUrl;
}
},
The problem being that getAccessToken()
needed to be called once again after window.location
is called. It was decided that calling getAccessToken()
in the else block after window.location
should be sufficient and thus solves this issue.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.