Reputation: 67
I'm trying to code a Music Player with React Hooks. This music player fetches the first five most famous songs of a band through the Deezer API.
When I click play/pause on any of the song it always plays the same song.
I know the problem is with useRef but I can't figure it out how to fix it. I read many tutorials and posts but nothing address this situation. Can somebody help? Thanks!
import React, { useState, useEffect } from 'react';
import './App.scss';
const BASE_URL = 'https://cors-anywhere.herokuapp.com/https://api.deezer.com/artist/182/top'
function MusicPlayer(){
const [ songs, setSongs ] = useState([])
const [ isLoading, setIsLoading ] = useState(false)
const [ error, setError ] = useState(null)
const inputRef = React.useRef()
useEffect(() => {
setIsLoading(true)
fetch(BASE_URL, {headers: {
"Accept": "application/json",
"Access-Control-Allow-Origin": "*"
}})
.then (res => {
return res.ok ? res.json() : throw new Error("Mistake!")
})
.then(songs => {
setSongs(songs.data)
setIsLoading(false)
})
.catch(error => {
setError(error)
})
}, [])
if (error){ return <p> { error.message }</p> }
if (isLoading ){ return <p> Loading songs...</p> }
return(
<div>
{ songs.map( (song, i) => (
<div key={i}>
<h1>{song.title}</h1>
<img src={song.contributors[0].picture_small}/><br/>
<audio ref={inputRef} src={song.preview} />
<button onClick={() => inputRef.current.play()}>Play</button>
<button onClick={() => inputRef.current.pause()}>Pause</button>
</div>
))
}
</div>
)
}
export default MusicPlayer
Upvotes: 1
Views: 1098
Reputation: 17259
This should do what you want:
import ReactDOM from "react-dom";
import React, { useState, useEffect } from "react";
const BASE_URL =
"https://cors-anywhere.herokuapp.com/https://api.deezer.com/artist/182/top";
function MusicPlayer() {
const [songs, setSongs] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
const [currentSong, setCurrentSong] = useState(null);
const inputRef = React.useRef();
useEffect(() => {
if (currentSong) {
inputRef.current.play();
}
console.log(currentSong);
}, [currentSong]);
useEffect(() => {
setIsLoading(true);
fetch(BASE_URL, {
headers: {
Accept: "application/json",
"Access-Control-Allow-Origin": "*"
}
})
.then(res => {
return res.ok ? res.json() : null;
})
.then(songs => {
setSongs(songs.data);
setIsLoading(false);
})
.catch(error => {
setError(error);
});
}, []);
if (error) {
return <p> {error.message}</p>;
}
if (isLoading) {
return <p> Loading songs...</p>;
}
const handlePlay = songPreview => {
if (currentSong) {
if (currentSong === songPreview) {
return inputRef.current.play();
}
}
setCurrentSong(songPreview);
};
return (
<div>
{songs.map((song, i) => (
<div key={i}>
<h1>{song.title}</h1>
<img src={song.contributors[0].picture_small} />
<br />
<audio ref={inputRef} src={currentSong} />
<button onClick={() => handlePlay(song.preview)}>Play</button>
<button onClick={() => inputRef.current.pause()}>Pause</button>
</div>
))}
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<MusicPlayer />, rootElement);
Basically, you need to keep track of what song is currently playing.
CodeSandbox demo here.
Upvotes: 3