用 React Hooks 构建的振荡器不会停止
Oscillator built with react hooks won't stop
我第一次尝试使用 WebAudio API 和 React。
我的想法是构建一个简单的按钮,单击该按钮即可启动或停止声音。
使用以下代码,我总是收到错误消息“无法在 'AudioNode' 上执行 'disconnect':给定的目的地未连接。”
我该如何解决?
谢谢!
import { useState } from 'react';
function App() {
const [ dataPlaying, setDataPlaying ] = useState(false)
const AudioContext = window.AudioContext || window.webkitAudioContext
const audioContext = new AudioContext()
let osc = audioContext.createOscillator()
osc.type = 'sine'
osc.frequency.value = 880
const createOscillator = () => {
if (dataPlaying === false) {
osc.start()
osc.connect(audioContext.destination)
setDataPlaying(true)
} else {
osc.disconnect(audioContext.destination)
setDataPlaying(false)
}
}
return (
<div className="App">
<button
onClick={() => createOscillator() }
data-playing={ dataPlaying }>
<span>Play/Pause</span>
</button>
</div>
);
}
export default App;
这是我解决连接错误的尝试。
- 在组件外部创建
AudioContext
。
- 使用
useRef
挂钩存储音频上下文以通过重新呈现持续存在。
- 使用
useEffect
挂钩实例化振荡器并管理音频上下文连接。
- 使用 start/stop 切换器暂停或恢复上下文,而不是 connect/disconnect 从中暂停或恢复上下文。
更新代码
import React, { useEffect, useRef, useState } from "react";
const AudioContext = window.AudioContext || window.webkitAudioContext;
export default function App() {
const [dataPlaying, setDataPlaying] = useState(false);
const audioContextRef = useRef();
useEffect(() => {
const audioContext = new AudioContext();
const osc = audioContext.createOscillator();
osc.type = "sine";
osc.frequency.value = 880;
// Connect and start
osc.connect(audioContext.destination);
osc.start();
// Store context and start suspended
audioContextRef.current = audioContext;
audioContext.suspend();
// Effect cleanup function to disconnect
return () => osc.disconnect(audioContext.destination);
}, []);
const toggleOscillator = () => {
if (dataPlaying) {
audioContextRef.current.suspend();
} else {
audioContextRef.current.resume();
}
setDataPlaying((play) => !play);
};
return (
<div className="App">
<button onClick={toggleOscillator} data-playing={dataPlaying}>
<span>{dataPlaying ? "Pause" : "Play"}</span>
</button>
</div>
);
}
我第一次尝试使用 WebAudio API 和 React。
我的想法是构建一个简单的按钮,单击该按钮即可启动或停止声音。
使用以下代码,我总是收到错误消息“无法在 'AudioNode' 上执行 'disconnect':给定的目的地未连接。”
我该如何解决? 谢谢!
import { useState } from 'react';
function App() {
const [ dataPlaying, setDataPlaying ] = useState(false)
const AudioContext = window.AudioContext || window.webkitAudioContext
const audioContext = new AudioContext()
let osc = audioContext.createOscillator()
osc.type = 'sine'
osc.frequency.value = 880
const createOscillator = () => {
if (dataPlaying === false) {
osc.start()
osc.connect(audioContext.destination)
setDataPlaying(true)
} else {
osc.disconnect(audioContext.destination)
setDataPlaying(false)
}
}
return (
<div className="App">
<button
onClick={() => createOscillator() }
data-playing={ dataPlaying }>
<span>Play/Pause</span>
</button>
</div>
);
}
export default App;
这是我解决连接错误的尝试。
- 在组件外部创建
AudioContext
。 - 使用
useRef
挂钩存储音频上下文以通过重新呈现持续存在。 - 使用
useEffect
挂钩实例化振荡器并管理音频上下文连接。 - 使用 start/stop 切换器暂停或恢复上下文,而不是 connect/disconnect 从中暂停或恢复上下文。
更新代码
import React, { useEffect, useRef, useState } from "react";
const AudioContext = window.AudioContext || window.webkitAudioContext;
export default function App() {
const [dataPlaying, setDataPlaying] = useState(false);
const audioContextRef = useRef();
useEffect(() => {
const audioContext = new AudioContext();
const osc = audioContext.createOscillator();
osc.type = "sine";
osc.frequency.value = 880;
// Connect and start
osc.connect(audioContext.destination);
osc.start();
// Store context and start suspended
audioContextRef.current = audioContext;
audioContext.suspend();
// Effect cleanup function to disconnect
return () => osc.disconnect(audioContext.destination);
}, []);
const toggleOscillator = () => {
if (dataPlaying) {
audioContextRef.current.suspend();
} else {
audioContextRef.current.resume();
}
setDataPlaying((play) => !play);
};
return (
<div className="App">
<button onClick={toggleOscillator} data-playing={dataPlaying}>
<span>{dataPlaying ? "Pause" : "Play"}</span>
</button>
</div>
);
}