Very new react user here. I am making a react app that displays albums from the spotify API. The problem is when you hit the search genre button it works and then when you hit the search new music button it works BUT when you try to use the search genre button again nothing happens. My code is probably very rough but here it is.
import { useEffect, useState } from "react";
import "./App.css";
const CLIENT_ID = "2a65aa062a2948b09f7af884b5447c3d";
const CLIENT_SECRET = "e93fd764678a4ebe97accd512e302219";
function App() {
const [accessToken, setAcessToken] = useState("");
const [albums, setAlbums] = useState([]);
const [genreAlbums, setGenreAlbums] = useState([]);
const [searchInput, setSearchInput] = useState("");
useEffect(() => {
// API Acess Token
var authParameters = {
method: "POST",
headers: {
"content-type": "application/x-www-form-urlencoded",
},
body:
"grant_type=client_credentials&client_id=" +
CLIENT_ID +
"&client_secret=" +
CLIENT_SECRET,
};
fetch("https://accounts.spotify.com/api/token", authParameters)
.then((result) => result.json())
.then((data) => setAcessToken(data.access_token));
}, []);
// Get new music
async function search() {
var newAlbums = await fetch(
"https://api.spotify.com/v1/browse/new-releases",
{
headers: {
Authorization: "Bearer " + accessToken,
},
}
)
.then((response) => response.json())
.then((data) => setAlbums(data.albums.items));
}
// Get specific genre
async function searchGenre() {
var newAlbumsGenre = await fetch(
'https://api.spotify.com/v1/search?type=track&q=genre:"' +
searchInput +
'"&limit=50',
{
headers: {
Authorization: "Bearer " + accessToken,
},
}
)
.then((response) => response.json())
.then((data) => setGenreAlbums(data.tracks.items));
console.log(genreAlbums);
}
return (
<div className="App">
<div>
<button className="button" type="button" onClick={search}>
Search for new music!
</button>
<form className="form">
<input
type="text"
id="genre"
autoComplete="off"
onChange={(event) => setSearchInput(event.target.value)}
/>
</form>
<button className="genreButton" type="button" onClick={searchGenre}>
Search Genre
</button>
</div>
<div>
{albums.map((album, i) => {
return (
<div className="card" key={i}>
<img src={album.images[0].url} alt="alt text" />
<div className="container">
<h4>
<b>{album.name}</b>
</h4>
<p>{album.artists[0].name}</p>
</div>
</div>
);
})}
</div>
<div>
{genreAlbums.map((track, i) => {
return (
<div className="card" key={i}>
<img src={track.album.images[0].url} alt="alt text" />
<div className="container">
<h4>
<b>{track.name}</b>
</h4>
<p>{track.artists[0].name}</p>
</div>
</div>
);
})}
</div>
</div>
);
}
export default App;
I have tried assigning keys to each of the mapped returns but nothing worked.
After seeing your code I have found issue in the state updation.
Problem: When you first search the genres than data will be stored in genreAlbums
state. Than you are rendering two different div with genres as well as music.
Now, After searching genres you are searching for music which will be stored in albums
but at that time genreAlbums is still not empty and it will lead to this unexpected behaviour.
Solution: Create one state which will keep track of which search you've clicked.
Here is the updated code (Link):
import { useEffect, useState } from "react";
const CLIENT_ID = "2a65aa062a2948b09f7af884b5447c3d";
const CLIENT_SECRET = "e93fd764678a4ebe97accd512e302219";
function App() {
const [accessToken, setAcessToken] = useState("");
const [albums, setAlbums] = useState([]);
const [genreAlbums, setGenreAlbums] = useState([]);
const [searchInput, setSearchInput] = useState("");
const [currentsearch, setCurrentSearch] = useState("");
useEffect(() => {
// API Acess Token
var authParameters = {
method: "POST",
headers: {
"content-type": "application/x-www-form-urlencoded",
},
body:
"grant_type=client_credentials&client_id=" +
CLIENT_ID +
"&client_secret=" +
CLIENT_SECRET,
};
fetch("https://accounts.spotify.com/api/token", authParameters)
.then((result) => result.json())
.then((data) => setAcessToken(data.access_token));
}, []);
// Get new music
async function search() {
var newAlbums = await fetch(
"https://api.spotify.com/v1/browse/new-releases",
{
headers: {
Authorization: "Bearer " + accessToken,
},
},
)
.then((response) => response.json())
.then((data) => setAlbums(data.albums.items));
setCurrentSearch("music");
}
// Get specific genre
async function searchGenre() {
var newAlbumsGenre = await fetch(
'https://api.spotify.com/v1/search?type=track&q=genre:"' +
searchInput +
'"&limit=50',
{
headers: {
Authorization: "Bearer " + accessToken,
},
},
)
.then((response) => response.json())
.then((data) => setGenreAlbums(data.tracks.items));
setCurrentSearch("genre");
}
return (
<div className="App">
<div>
<button className="button" type="button" onClick={search}>
Search for new music!
</button>
<form className="form">
<input
type="text"
id="genre"
autoComplete="off"
onChange={(event) => setSearchInput(event.target.value)}
/>
</form>
<button className="genreButton" type="button" onClick={searchGenre}>
Search Genre
</button>
</div>
{currentsearch === "music" ? (
<div>
{albums.map((album, i) => {
return (
<div className="card" key={i}>
<img src={album.images[0].url} alt="alt text" />
<div className="container">
<h4>
<b>{album.name}</b>
</h4>
<p>{album.artists[0].name}</p>
</div>
</div>
);
})}
</div>
) : (
<div>
{genreAlbums.map((track, i) => {
return (
<div className="card" key={i}>
<img src={track.album.images[0].url} alt="alt text" />
<div className="container">
<h4>
<b>{track.name}</b>
</h4>
<p>{track.artists[0].name}</p>
</div>
</div>
);
})}
</div>
)}
</div>
);
}
export default App;
Let me know, if you have any questions.