I am currently working on a music player in React.
So far I have a Context Provider with a music element stored with the useState
hook.
const [currentSong, setCurrentSong] = useState(null);
useEffect(() => {
fetchSong();
}, []);
const fetchSong = () => {
const songAudio = new Audio(`localhost/song/13/audio`)
songAudio.onloadeddata = () => {
songAudio.play();
setCurrentSong(songAudio);
}
}
After that the currentSong Object looks something like this
<audio preload="auto" src="http://localhost/song/13/audio">
{...}
duration: 239.081
currentTime: 113.053
{...}
<prototype>: HTMLAudioElementPrototype { … }
Because the song is playing the currentTime gets updated automatically.
My question is if it is possible to trigger a rerender every time currentTime
changes so that I can update a span element with that number.
The span is in a seperate file and consumes the Context Provider which provides the currentSong
object.
const { currentSong, {...} } = useMusicContext();
{...}
return (
<span className='...'>
{currentSong? currentSong.currentTime: "0:00"}
</span>
)
The problem is that the component does not know that the currentTime
value changed and only updates the text if a rerender is triggered by something else.
CodePudding user response:
Add an event listener to the audio element for timeupdate events and use those to update your state (or whatever).
Here's a quick demo implementation. Source included below for easier reference.
// Audio component to handle attaching the listener
import { useEffect, useRef } from "react";
export function Audio({ onTimeUpdate, ...props }) {
const audioRef = useRef();
useEffect(() => {
const { current } = audioRef;
current?.addEventListener("timeupdate", onTimeUpdate);
return () => current?.removeEventListener("timeupdate", onTimeUpdate);
}, [audioRef, onTimeUpdate]);
return (
<audio ref={audioRef} {...props} />
);
}
export default function App() {
const [time, setTime] = useState();
const onTimeUpdate = (e) => {
setTime(e.target.currentTime);
};
return (
<div className="App">
<Audio onTimeUpdate={onTimeUpdate} controls src="./audio-sample.mp3" />
<div>{time}</div>
</div>
);
}
CodePudding user response:
Tough to exactly say what to do here - would need more info/code, but I do believe that passing down currentTime
as a prop would work.
If that is not possible, or you don't want to keep passing down props, you may want to look into the react hook called useContext
.
Alternatively, perhaps you could use useEffect
to trigger re-renders in the component you want to update. Not exactly sure how you would trigger this re-render/what you would put in the dependency array without more info.