We are trying to populate an array with songs using the Spotify API.
The API allows you to grab 50 songs at once, so we created a loop using an offset
to get 250 songs.
After we get the songs, I want to update this.state.searchResults
to hold the songs (with some filtering on the results).
But, when we use setState
, thee array is not updated. I have done some research on this and I understand setState
is async, and that the array is immutable but the solutions I found did not work.
In App.js:
import React, { Component } from "react";
import SearchBar from "../SearchBar/SearchBar";
import SearchResults from "../SearchResults/SearchResults";
import Playlist from "../Playlist/Playlist";
import "./App.css";
import Spotify from "../../util/Spotify";
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
searchResults: [],
playlistName: "New Playlist",
playlistTracks: [],
};
this.addTrack = this.addTrack.bind(this);
this.removeTrack = this.removeTrack.bind(this);
this.savePlaylist = this.savePlaylist.bind(this);
this.updatePlaylistName = this.updatePlaylistName.bind(this);
this.search = this.search.bind(this);
}
componentDidMount() {
window.addEventListener("load", () => {
Spotify.getAccessToken();
});
}
addTrack(track) {
if (
!this.state.playlistTracks.find(
(playlistTrack) => playlistTrack.id === track.id
)
) {
this.setState((prevState) => ({
playlistTracks: [...prevState.playlistTracks, track],
}));
}
}
removeTrack(track) {
this.setState({
playlistTracks: this.state.playlistTracks.filter(
(playlistTrack) => playlistTrack.id !== track.id
),
});
}
updatePlaylistName(name) {
this.setState({ playlistName: name });
}
savePlaylist() {
const trackUris = this.state.playlistTracks.map(
(playlistTrack) => playlistTrack.uri
);
Spotify.savePlaylist(this.state.playlistName, trackUris).then(() => {
this.setState({ playlistName: "another new one", playlistTracks: [] });
});
}
search(term) {
let temp = [];
for (let i = 0; i < 5; i++) {
Spotify.search(term, (i * 50).toString()).then((response) => {
response.forEach(function (arrayTrack) {
temp.push(arrayTrack);
});
});
}
this.setState((prevState) => ({
searchResults: [...prevState.searchResults, ...temp],
}));
console.log("temp= ", temp);
console.log("searhResults= ", this.state.searchResults);
}
render() {
console.log("this.state.searchresults:", this.state.searchResults);
return (
<div>
<h1>
Ja<span className="highlight">mmm</span>ing
</h1>
<div className="App">
<SearchBar onSearch={this.search} />
<div className="App-playlist">
<SearchResults
onSearch={this.search}
searchResults={this.state.searchResults}
onAdd={this.addTrack}
/>
<Playlist
name={this.state.playlistName}
tracks={this.state.playlistTracks}
onRemove={this.removeTrack}
onNameChange={this.updatePlaylistName}
onSave={this.savePlaylist}
/>
</div>
</div>
</div>
);
}
}
export default App;
In Spotify.js:
search(term, offset) {
const accessToken = Spotify.getAccessToken();
return fetch(
`https://api.spotify.com/v1/search?type=track&q=year:${term}&limit=50&offset=${offset}`,
{
headers: {
Authorization: `Bearer ${accessToken}`,
},
}
)
.then((response) => {
if (response.ok) {
return response.json();
}
})
.then((jsonResponse) => {
if (!jsonResponse.tracks) {
return [];
} else {
var results = [];
results = jsonResponse.tracks.items.map((track) => ({
id: track.id,
name: track.name,
artist: track.artists[0].name,
album: track.album.name,
uri: track.uri,
release_date: track.album.release_date,
release_date_precisions: (track.album.release_date_precision =
"month"),
}));
var filtered_results = [];
results.forEach(function (arrayTrack) {
if (arrayTrack.release_date.includes(`${term}-10`)) {
filtered_results.push(arrayTrack);
}
});
console.log(results);
console.log("filtered results for i= ", filtered_results);
return filtered_results;
}
});
},
The console shows temp is populated correctly, but searchResults is empty:
App.js:95
temp= \[\]0: {id: '60a0Rd6pjrkxjPbaKzXjfq', name: 'In the End', artist: 'Linkin Park', album: 'Hybrid Theory (Bonus Edition)', uri: 'spotify:track:60a0Rd6pjrkxjPbaKzXjfq', …}
1: {id: '0I3q5fE6wg7LIfHGngUTnV', name: 'Ms. Jackson', artist: 'Outkast', album: 'Stankonia', uri: 'spotify:track:0I3q5fE6wg7LIfHGngUTnV', …}
2: {id: '3IV4swNduIRunHREK80owz', name: "Rollin' (Air Raid Vehicle)",
.......
App.js:96
searhResults= \[\]length: 0\[\[Prototype\]\]: Array(0)......
I have tried a variety of ways to update the array. The current method was taken from a website that discussed the immutability of the array.
The first thing I tried was this.setState({ searchResults: searchResults });
which of course doesn't work.
However, if you do the following:
this.setState({ searchResults: temp }, () => {
console.log(this.state.searchResults);
});
console.log(this.state.searchResults);
the first console.log will print searchResults populated correctly. But the second console.log return an empty array. I don't understand why that happens.