import { useState } from "react";
function Music(){
const [pauseToggle, setpauseToggle] = useState(false)
const music = new Audio(require(`./Alan.mp3`));
console.log(music);
let isPlaying = false;
const player = () => {
pauseToggle ? setpauseToggle(false) : setpauseToggle(true);
if(isPlaying){
music.pause();
isPlaying = false;
}else{
music.play();
isPlaying = true;
}
}
return(
<div>
<button onClick={player}>{pauseToggle?"=":">"}</button>
</div>
)
}
export default Music;
I'm unable to pause the audio, instead it gets played twice when I try to pause. I tried to get help from this Unable to pause audio in Reactjs but it didn't helped
Any other solution for pausing audio file?
Thank You in advance
CodePudding user response:
I believe the music variable should be stateful so it's retained across renders.
const [music] = useState(new Audio(require(`./Alan.mp3`)));
and isPlaying should probably be found by querying the Audio object (music) and/or updated by listening for play/pause state changes.
CodePudding user response:
I'd simplify state to a single boolean: your audio is either playing or not, so there's no need for redundancy here. let isPlaying = false; isn't state, so it's not persistent across renders and doesn't do anything pauseToggle doesn't already achieve.
Since the audio is a side effect to the rendering, I'd make it a ref, then trigger play/pause functions based on when playing changes in a useEffect.
A bit of a bonus, but it's probably worth handling the onended event to set playing to false when the track ends, for starters.
const {useEffect, useRef, useState} = React;
const MusicPlayer = ({url}) => {
const [playing, setPlaying] = useState(false);
const audioRef = useRef(new Audio(url));
useEffect(() => {
const handler = () => setPlaying(false);
audioRef.current.addEventListener("ended", handler);
return () =>
audioRef.current.removeEventListener("ended", handler)
;
}, [audioRef.current]);
useEffect(() => {
audioRef.current[playing ? "play" : "pause"]();
}, [playing]);
return (
<div>
<button onClick={() => setPlaying(!playing)}>
{playing ? "=" : ">"}
</button>
</div>
);
};
const url = "https://upload.wikimedia.org/wikipedia/en/a/a9/Webern_-_Sehr_langsam.ogg";
ReactDOM.render(
<MusicPlayer url={url}/>,
document.querySelector("#app")
);
button {
font-size: 2em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="app"></div>
Putting the audio into a hook helps make it reusable and keeps your parent component clean:
const {useEffect, useRef, useState} = React;
const useAudio = url => {
const [playing, setPlaying] = useState(false);
const audioRef = useRef(new Audio(url));
useEffect(() => {
const handler = () => setPlaying(false);
audioRef.current.addEventListener("ended", handler);
return () =>
audioRef.current.removeEventListener("ended", handler)
;
}, [audioRef.current]);
useEffect(() => {
audioRef.current[playing ? "play" : "pause"]();
}, [playing]);
return [playing, setPlaying];
};
const MusicPlayer = ({url}) => {
const [playing, setPlaying] = useAudio(url);
return (
<div>
<button onClick={() => setPlaying(!playing)}>
{playing ? "=" : ">"}
</button>
</div>
);
};
const url = "https://upload.wikimedia.org/wikipedia/en/a/a9/Webern_-_Sehr_langsam.ogg";
ReactDOM.render(
<MusicPlayer url={url}/>,
document.querySelector("#app")
);
button {
font-size: 2em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="app"></div>
