Reputation: 753
So I have this button:
<button onClick={this.setRecommendations}>
log into Spotify
</button>
Calls this function:
setRecommendations(){
recommendations().then(recs => {
this.setState({recommendations: recs});
});
}
Which calls this function:
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;
}
Which calls another function and another function ultimately one of the first things it does is call 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 functions ultimately work but you have to click the button twice. Last night I tried putting some console.log()
s to see what was happening and then I realized that this.setRecommendation
doesn't seem like it is being called until the second click. but the button still took you to the login screen so somehow it was getting to getAccessToken
:
I even tried:
setRecommendations(){
console.log("you pushed the button");
recommendations().then(recs => {
this.setState({recommendations: recs});
});
}
And "you pushed the button" would still not be console logged until the second click, but again it would take you to the login, so I created a second function login()
an all it does is call getAccessToken()
:
login(){
Spotify.getAccessToken();
}
So I have two buttons, one calls this.login
the other calls this.setRecommendations
when I click this.login
and then this.setRecommendations
it works as you expected, populates the components nicely.
But I would still like this to be one click. I tried:
<button onClick={() => {
this.login();
this.setRecommendations();}}>
log into Spotify
</button>
But that doesn't work it still calls this.login()
and doesn't seem to call this.setRecommendations()
until once again the second click.
this is my App Component
import React from 'react';
import './App.css';
import {Spotify, recommendations} from '../../utils/Spotify';
import RecommendationButton from '../RecommendationButton/RecommendationButton';
import Playlist from '../Playlist/Playlist';
import Graphs from '../Graphs/Graphs'
import RecommendationResults from '../RecommendationResults/RecommendationResults';
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.login = this.login.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});
});
}
login(){
Spotify.getAccessToken();
}
setRecommendations(){
recommendations().then(recs => {
console.log(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() {
return (
<div>
<h1>Spotify Recommendations</h1>
<div className="App">
<button onClick={this.login}>
log into Spotify
</button>
<RecommendationButton onPush={this.setRecommendations} />
<Graphs data={this.state.album_count} margins={this.state.topAlbums} graphID={"topAlbums"} />
<div className="Graphs">
<Graphs data={this.state.artist_count} margins={this.state.topArtist} graphID={"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>
);
}
}
export default App;
Upvotes: 0
Views: 116
Reputation: 141
Do you need the Access Token before you are able to get the recommendations?
It may be the case that on the first click the program does not yet have the access token needed to get the recommendations and that's why it takes two clicks, because there is a pause for it to get the access token between the two clicks. This may be caused by the following line in getAccessToken
:
window.setTimeout(() => accessToken = '', expiresIn * 1000);
You could try having getAccessToken()
return a promise with the resolve value being the access token. And then in your login function call getAccessToken
and .then()
setRecommendations
.
In your JSX you would just have onClick={this.login}
.
Upvotes: 1