React/Next.js中访问Audio ref获取音频时长返回NaN问题
问题根因
这个现象和SSR无关,本质是音频元数据加载是异步流程。你在useEffect中刚创建Audio实例、传入src路径后立刻读取duration属性时,浏览器还没完成音频文件的元数据拉取和解析,此时duration的默认值就是NaN。
你在控制台console.log(audioRef)能看到13秒的时长,是因为浏览器控制台对对象类型的打印是懒求值的:你手动点开控制台里的对象折叠项时,才会读取对象当下的最新属性值,这时候音频早就加载完了,自然能看到正确时长,但你执行console.log(audioRef.current.duration)的那一瞬间,值确实是NaN,控制台没有返回错误结果。
修复代码
不要在创建Audio实例后同步读取duration,监听Audio元素原生的loadedmetadata事件,等元数据解析完成后再取值更新状态即可,同时记得组件卸载时做事件和实例清理,避免内存泄漏:
const EXAMPLE_TRACK = { title: "Track Title", src: "http://goldfirestudios.com/proj/howlerjs/sound.ogg" } const Track = ({track = EXAMPLE_TRACK}) => { const [duration, setDuration] = useState(0); const audioRef = useRef(null); useEffect(() => { const audioInstance = new Audio(track.src); audioRef.current = audioInstance; const onMetadataLoaded = () => { setDuration(audioInstance.duration); }; audioInstance.addEventListener('loadedmetadata', onMetadataLoaded); return () => { audioInstance.removeEventListener('loadedmetadata', onMetadataLoaded); audioInstance.pause(); audioRef.current = null; }; }, [track.src]); return ( <> <div>标题:{track.title}</div> <div>时长:{duration}秒</div> </> ); }
排查提示
后续调试异步相关的变量时,不要直接信任控制台打印的对象快照——对象的懒求值特性在异步场景下非常容易误导判断。如果需要确认代码执行瞬间的对象值,可以直接打印原始类型字段,或者用console.log(JSON.stringify(目标对象))输出深拷贝后的静态快照。
如果遇到部分浏览器loadedmetadata触发不及时的场景,可以额外加个durationchange事件监听做兜底,回调逻辑和上面的元数据加载回调一致即可。
内容的提问来源于stack exchange,提问作者sea_monster
相关产品推荐
相关产品推荐

