skip to Main Content

I’m trying to make a React Music Player but I don’t know why, the volume is not updating in real time. The volume only changes whenever I stop the audio and then play it again.

const [volume, setVolume] = useState(1)
    const [isPlaying, setIsPlaying] = useState(false);
    const audioRef = React.createRef();

    const togglePlay = () => {
        const audio = audioRef.current;

        if (!audio) return;

        audio.volume = volume;

        if (isPlaying) {
            audio.volume = 0;
        } else {
            audio.volume = Number(volume);
            audio.play();
            console.log(volume)
        }

        setIsPlaying((prevIsPlaying) => !prevIsPlaying);
    };

The input:

<input type="range" value={volume} onChange={(e) => setVolume(parseFloat(e.target.value))} max="1" min="0"/>

I’ve tried to use Chat-GPT to help me fix this error

2

Answers


  1. I would use the useEffect React hook, in order to keep the state data consistent with the (HTML) Audio object.

    So every time either volume or isPlaying variable is changed, the hook is then executed, and by comparing the values of the actual Audio object and your state, you would depending on the variable changed; either call the Audio API or change the Audio refs value.

    const YourComponent = () => {
      const [volume, setVolume] = React.useState(0.3);
      const [isPlaying, setIsPlaying] = React.useState(false);
      const audioRef = React.useRef();
    
      React.useEffect(() => {
          const audio = audioRef.current;
          if (!audio) return;
          if (audio.volume !== volume) {
            audio.volume = volume;
          }
          if (!audio.paused !== isPlaying) {
            isPlaying ? audio.play() : audio.pause();
          }
      }, [volume, isPlaying]);
    
      const togglePlay = () => {
        setIsPlaying((prevIsPlaying) => !prevIsPlaying);
      }
    
      return (
        <div>
          <audio volume={volume} ref={audioRef}>
            <source src="https://codeskulptor-demos.commondatastorage.googleapis.com/GalaxyInvaders/theme_01.mp3" type="audio/mpeg"/>
          </audio>
          <input type="range" step="0.1" value={volume} onChange={(e) => setVolume(parseFloat(e.target.value))} max="1" min="0"/>
          <button onClick={togglePlay}>{isPlaying ? 'Pause' : 'Play'}</button>
        </div>
      );
    }
    
    ReactDOM.render(<YourComponent />, document.getElementById("root"));
    <div id="root"></div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>

    PS: Remember, autoplay is usually blocked by browsers. https://developer.mozilla.org/en-US/docs/Web/Media/Autoplay_guide

    Login or Signup to reply.
  2. How about to use useEffect hook?
    Like this :

    useEffect(() => {
    const audio = audioRef.current;
    if (!audio) return;
    audio.volume = volume;
    }, [volume]);

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search