useState 保持之前的状态
useState keeps the previous state
在我的应用程序中,我点击 Play
按钮,音频应该开始播放,当它结束时语音识别应该开始收听,当它结束时应该在控制台中打印消息(它将更改为一些其他操作进一步)。
如果我单击 stop
按钮,我的应用程序还具有停止识别过程的功能,为此我使用 useState
,其中 false
状态更改为 true
。
但是,我遇到了一个问题:当我尝试通过单击 Stop
按钮停止收听时,状态变为 true
并且它应该在此处停止,但尽管如此我有 if(isPlaying === false)
条件,在 true
之后,作为最后一个操作,我在控制台中得到 false
♂️ 为什么会这样,如何解决?
const [song] = useState(typeof Audio !== 'undefined' && new Audio())
const [isPlaying, setIsPlaying] = useState(false)
function playSong() {
setIsPlaying(!isPlaying)
if (listening) {
SpeechRecognition.stopListening()
}
if (isPlaying === false) {
song.src = 'https://raw.songToPlay.mp3'
song.play()
console.log('Song is playing: ' + isPlaying)
song.addEventListener('ended', () => {
console.log('Recognition is started: ' + isPlaying)
SpeechRecognition.startListening()
})
recognition.addEventListener('audioend', () => {
console.log('Recognition is finished: ' + isPlaying)
})
} else {
console.log('When stop is clicked: ' + isPlaying)
}
}
return (
<div>
<p>Microphone: {listening ? 'on' : 'off'}</p>
<button onClick={playSong}>{isPlaying ? 'Stop' : 'Play'}</button>
<p>{transcript}</p>
</div>
)
输出:
从 playSong 中记录状态将在定义函数时记录状态。这意味着该值将过时,即陈旧。这是因为称为闭包的功能概念。来自 Wikipedia “与普通函数不同,闭包允许函数通过闭包的值或引用的副本访问那些捕获的变量,即使函数是在其范围之外调用的。”
那么当状态改变时,我们应该如何记录当前状态呢?通过使用 useEffect 钩子。每当任何依赖项发生变化时,此函数都会 re-run。
您还可以 return 一个 'cleanup' 函数来删除侦听器等
const [isPlaying, setIsPlaying] = useState(false);
useEffect(() => {
if (!isPlaying) {
console.log("Starting to play");
// add your event listener here to wait for song to end and start speech recognition
} else {
console.log("When stop is clicked: " + isPlaying);
// stop your speech recognition here
}
return () => {
// this is a cleanup function - you can use it to remove event listeners so you don't add them twice
};
}, [isPlaying]);
return (
<div>
<button onClick={() => setIsPlaying(!isPlaying)}>
{isPlaying ? "Stop" : "Play"}
</button>
</div>
);
在我的应用程序中,我点击 Play
按钮,音频应该开始播放,当它结束时语音识别应该开始收听,当它结束时应该在控制台中打印消息(它将更改为一些其他操作进一步)。
如果我单击 stop
按钮,我的应用程序还具有停止识别过程的功能,为此我使用 useState
,其中 false
状态更改为 true
。
但是,我遇到了一个问题:当我尝试通过单击 Stop
按钮停止收听时,状态变为 true
并且它应该在此处停止,但尽管如此我有 if(isPlaying === false)
条件,在 true
之后,作为最后一个操作,我在控制台中得到 false
♂️ 为什么会这样,如何解决?
const [song] = useState(typeof Audio !== 'undefined' && new Audio())
const [isPlaying, setIsPlaying] = useState(false)
function playSong() {
setIsPlaying(!isPlaying)
if (listening) {
SpeechRecognition.stopListening()
}
if (isPlaying === false) {
song.src = 'https://raw.songToPlay.mp3'
song.play()
console.log('Song is playing: ' + isPlaying)
song.addEventListener('ended', () => {
console.log('Recognition is started: ' + isPlaying)
SpeechRecognition.startListening()
})
recognition.addEventListener('audioend', () => {
console.log('Recognition is finished: ' + isPlaying)
})
} else {
console.log('When stop is clicked: ' + isPlaying)
}
}
return (
<div>
<p>Microphone: {listening ? 'on' : 'off'}</p>
<button onClick={playSong}>{isPlaying ? 'Stop' : 'Play'}</button>
<p>{transcript}</p>
</div>
)
输出:
从 playSong 中记录状态将在定义函数时记录状态。这意味着该值将过时,即陈旧。这是因为称为闭包的功能概念。来自 Wikipedia “与普通函数不同,闭包允许函数通过闭包的值或引用的副本访问那些捕获的变量,即使函数是在其范围之外调用的。”
那么当状态改变时,我们应该如何记录当前状态呢?通过使用 useEffect 钩子。每当任何依赖项发生变化时,此函数都会 re-run。
您还可以 return 一个 'cleanup' 函数来删除侦听器等
const [isPlaying, setIsPlaying] = useState(false);
useEffect(() => {
if (!isPlaying) {
console.log("Starting to play");
// add your event listener here to wait for song to end and start speech recognition
} else {
console.log("When stop is clicked: " + isPlaying);
// stop your speech recognition here
}
return () => {
// this is a cleanup function - you can use it to remove event listeners so you don't add them twice
};
}, [isPlaying]);
return (
<div>
<button onClick={() => setIsPlaying(!isPlaying)}>
{isPlaying ? "Stop" : "Play"}
</button>
</div>
);