如果使用 useState React Tonejs 则无法停止播放器

Cannot stop player if use useState React Tonejs

我正在尝试使用 tonejs 库在我的 React 项目中实现一个 start/stop 按钮,但是在我使用 setState 更改我的图标后,我的 player.stop() 功能不起作用.如果我再按 2 次按钮,第二个播放器会发出声音。

这是我的代码

    const [play, setPlay] = useState(false);
    const buffer = new Tone.Buffer("audio.mp3");
    const player = new Tone.Player(buffer).toDestination();

    const startMusic = () => {
        if (buffer.loaded) {
            player.start();
            setPlay(true);
        }
    }

    const muteMusic = () => {
        player.stop();
        console.log(player.buffer)
        setPlay(false);
    }

<Avatar className="hover" style={{ position: 'absolute', top: '10px', left: '10px' }}>
     {play == true ? <VolumeUpRounded onClick={() => { muteMusic() }} /> : <VolumeOff onClick={() => { startMusic() }} />}
</Avatar>

更新: 现在我使用 ContextProvider 来只控制音频,我调用儿童

中的函数
import { createContext } from "react";
import * as Tone from "tone";
import chopin from "../assets/songs/audio.mp3"

const AudioContext = createContext({
    start: null,
    stop: null,

})

export default AudioContext;

export const AudioContextProvider = (props) => {

    const buffer = new Tone.Buffer(chopin);
    const player = new Tone.Player(buffer).toDestination();

    const start = () => {
        player.start();
        console.log('started!');

    }
    const stop = () => {
        player.stop(); 
        console.log('stopped');
    }


    return (
        <AudioContext.Provider value={{
            start: start,
            stop: stop,
        }}>
            {props.children}
        </AudioContext.Provider>
    )
}

并像这样使用:

import AudioController from "../context/audio-context-controller";

const audioController = React.useContext(AudioController);
const [started, setStarted] = useState(false);


const start = () => {
    audioController.start();
    setStarted(true);
}
    
const stop = () => {
    audioController.stop();
    setStarted(false);
}

如上所述,setState 方法生成的渲染始终允许您拥有一个新的播放器实例,突然间您无法访问该对象的当前状态。

背后的想法是在组件外部有一个实例,即使组件是 re-rendered,你也将始终拥有相同的 Player 实例。

const player = new Tone.Player("https://www.soundhelix.com/examples/mp3/SoundHelix-Song-5.mp3").toDestination();
  
function Example() {
  const [play, setPlay] = useState(false);
  
 
    const startMusic = () => {
            player.start();
            setPlay(true);
        
    }
    const muteMusic = () => {
        player.stop();
        setPlay(false);
    }

  return (
    <div>
      <button onClick={play===true ? muteMusic : startMusic}>
        {play ===true ? "stop" : "start"}
      </button>
    </div>
  );
}

考虑创建一个服务,这样您将始终在应用程序上获得一个单例。