如何在React(Next.js)中使用wavesurfer.js?容器未找到报错如何解决
问题修复方案
你遇到的Container element not found报错核心原因是初始化WaveSurfer实例时,传入的容器ref尚未指向实际DOM节点,可按以下说明修改代码:
核心问题说明
- 缺少容器ref存在性校验:创建实例前未判断ref是否已绑定DOM,直接传入空值触发报错
- 异步加载存在竞态:动态import wavesurfer.js是异步操作,若组件在import完成前卸载,后续初始化逻辑依然会执行,此时ref已被清空
- useEffect依赖配置错误:注释标注音频地址变更时需重新初始化实例,但依赖数组为空,音频更新后不会触发重新初始化
- 实例方法调用未加校验:播放状态联动逻辑中直接调用wavesurfer实例方法,若实例未创建完成会触发额外报错
修复后完整代码
const formWaveSurferOptions = (ref) => ({ container: ref, waveColor: '#ffc600', progressColor: '#c79b03', cursorColor: '#c79b03', barWidth: 3, barRadius: 3, responsive: true, height: 53, overflow: 'hidden', normalize: true, partialRender: true, }); export function Player({ className, id, audio, audioPlayId, setAudioPlayId, ...props }: PlayerProps): JSX.Element { const waveformRef = useRef(null); const wavesurfer = useRef(null); const [playing, setPlay] = useState(false); const [volume, setVolume] = useState(0.5); const [isLoaded, setIsLoaded] = useState(false); // 播放当前组件音频时暂停其余所有音频 useEffect(() => { if (audioPlayId && audioPlayId !== id && wavesurfer.current) { setPlay(false) wavesurfer.current.pause() } }, [audioPlayId, id]) // 组件挂载或音频地址变更时创建新的WaveSurfer实例 useEffect(() => { // 标记组件是否处于挂载状态,解决异步竞态问题 let isMounted = true; // 先销毁之前的旧实例,避免重复创建 if (wavesurfer.current) { wavesurfer.current.destroy(); wavesurfer.current = null; setIsLoaded(false); } import('wavesurfer.js').then((m) => { // 组件已卸载、容器ref未绑定、实例已存在的情况下直接终止逻辑 if (!isMounted || !waveformRef.current || wavesurfer.current) return; const WaveSurfer = m.default; setPlay(false); const options = formWaveSurferOptions(waveformRef.current); wavesurfer.current = WaveSurfer?.create(options); wavesurfer.current.load(audio); wavesurfer.current.on('ready', function () { if (!wavesurfer.current) return; wavesurfer.current.setVolume(volume); setIsLoaded(true) }); }); // 组件卸载或依赖变更时的清理逻辑 return () => { isMounted = false; wavesurfer?.current?.destroy(); wavesurfer.current = null; } }, [audio, volume]); const handlePlayPause = (e): void => { e.preventDefault(); e.stopPropagation(); if (!wavesurfer.current) return; setPlay(!playing); wavesurfer.current.playPause(); setAudioPlayId(id) }; return ( <div className={className}> <div className={styles.palyer_container}> <div id={styles.waveform} ref={waveformRef} /> {isLoaded ? <div className="controls"> <Button appearance="container" onClick={handlePlayPause}>{!playing ? <PlayIcon /> : <PauseIcon />}</Button> </div> : <Loader />} </div> </div > ); }
内容的提问来源于stack exchange,提问作者Pavel Shilyaev
相关产品推荐
相关产品推荐

