Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

listen to deeply nested react state

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.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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.

>Solution :

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>
  );
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading