Next.js中window.speechSynthesis.getVoices页面刷新失效求助
问题原因分析
- SpeechSynthesis API的语音资源加载是异步过程,
window.speechSynthesis.getVoices()仅在浏览器完成语音资源加载后才会返回有效列表。 - 首次加载时,浏览器可能已缓存语音资源,
useEffect空依赖回调执行时资源已就绪,因此能正常获取数据;但页面刷新时,语音资源需要重新加载,此时useEffect执行过早,导致getVoices()返回空数组。 - 原代码未监听
voiceschanged事件——该事件会在语音列表加载完成或发生变化时触发,无法捕获异步加载完成的时机。
解决方案
在useEffect中补充voiceschanged事件监听,确保语音资源加载完成后更新状态,同时适配Next.js的SSR特性(判断window存在性),并做好事件清理避免内存泄漏:
import { useState, useEffect } from 'react'; export default function Home() { const [voices, setVoices] = useState<SpeechSynthesisVoice[]>([]); useEffect(() => { const updateVoices = () => { if (window?.speechSynthesis) { setVoices(window.speechSynthesis.getVoices()); } }; // 先尝试获取一次,覆盖资源已提前加载的场景 updateVoices(); // 监听语音加载完成事件 window.speechSynthesis.addEventListener('voiceschanged', updateVoices); // 组件卸载时清理监听 return () => { window.speechSynthesis.removeEventListener('voiceschanged', updateVoices); }; }, []); return ( <div> <h1>可用语音列表</h1> <ul> {voices.map(voice => ( <li key={voice.voiceURI}>{voice.name} ({voice.lang})</li> ))} </ul> </div> ); }
关键说明
updateVoices函数封装获取逻辑,通过window?.speechSynthesis判断避免Next.js服务端渲染时的报错。- 主动调用
updateVoices处理首次加载时资源已就绪的情况。 voiceschanged事件监听确保在语音资源异步加载完成后更新状态,彻底解决刷新后返回空数组的问题。- 清理函数移除事件监听,防止内存泄漏。
内容的提问来源于stack exchange,提问作者hinsano
相关产品推荐
相关产品推荐

