You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在React(Next.js)中使用wavesurfer.js?容器未找到报错如何解决

问题修复方案

你遇到的Container element not found报错核心原因是初始化WaveSurfer实例时,传入的容器ref尚未指向实际DOM节点,可按以下说明修改代码:

核心问题说明

  1. 缺少容器ref存在性校验:创建实例前未判断ref是否已绑定DOM,直接传入空值触发报错
  2. 异步加载存在竞态:动态import wavesurfer.js是异步操作,若组件在import完成前卸载,后续初始化逻辑依然会执行,此时ref已被清空
  3. useEffect依赖配置错误:注释标注音频地址变更时需重新初始化实例,但依赖数组为空,音频更新后不会触发重新初始化
  4. 实例方法调用未加校验:播放状态联动逻辑中直接调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 18:45:01