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

cant change the volume of music after it starts playing

I am trying to make a simple component that when you press a button, will start playing a looping song which you could control the volume of using a range input.

This is my code so far:

import { useState, useEffect } from "react";
import music from "./assets/music.mp3";

function MusicPlay() {
  const [volume, setVolume] = useState(20);
  const testMusic = new Audio(music);
  const playMusic = () => {
    testMusic.play();
    testMusic.volume = volume / 100;
    testMusic.loop = true;
    console.log("started music", testMusic, testMusic.volume);
  };

  useEffect(() => {
    testMusic.volume = volume / 100;
    console.log("changed volume", testMusic, testMusic.volume);
  }, [volume]);

  return (
    <div className="App">
      <button onClick={playMusic}>Play</button>
      <input
        type="range"
        min="0"
        max="100"
        step="1"
        value={volume}
        onChange={(e) => {
          setVolume(Number(e.target.value));
        }}
      />
    </div>
  );
}

export default MusicPlay;

right now you can press the button to start music, and it will start at the volume you specified, but when you move the slider it doesnt update the volume

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

>Solution :

Every render of this component will create a new instance of Audio. Changing the volume will cause a rerender. This means that you lost the reference to your playing Audio quite a while ago. If you store the audio in a ref, you’ll always refer to the same audio and be able to change it’s volume:

import React, { useState, useEffect, useRef } from "react";
import music from "./assets/music.mp3";

function MusicPlay() {
  const [volume, setVolume] = useState(20);
  const testMusicRef = useRef();
  React.useEffect(() => {
    if (!testMusicRef.current) {
      testMusicRef.current = new Audio(music);
    }
  }, []);
  const playMusic = () => { // consider wrapping this in useCallback too
    if (!testMusicRef.current) {
      return;
    }
    testMusicRef.current.play();
    testMusicRef.current.volume = volume / 100;
    testMusicRef.current.loop = true;
    console.log(
      "started music",
      testMusicRef.current,
      testMusicRef.current.volume
    );
  };

  useEffect(() => {
    if (!testMusicRef.current) {
      return;
    }
    testMusicRef.current.volume = volume / 100;
    console.log(
      "changed volume",
      testMusicRef.current,
      testMusicRef.current.volume
    );
  }, [volume]);

  return (
    <div className="App">
      <button onClick={playMusic}>Play</button>
      <input
        type="range"
        min="0"
        max="100"
        step="1"
        value={volume}
        onChange={(e) => {
          setVolume(Number(e.target.value));
        }}
      />
    </div>
  );
}

export default MusicPlay;

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