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

React音频组件状态问题:如何仅更新单个元素的state

解决React多音频组件状态同步更新问题

你的问题核心在于所有音频共用了同一组全局状态(current、dur、bar),不管操作哪个音频,调用setState都会更新这几个全局变量,导致所有音频的进度信息同步变化。

解决方案:拆分独立子组件

把单个音频的UI和状态封装成独立的AudioItem组件,让每个音频实例自己管理专属状态,这样状态更新只会影响当前音频。

修改后的完整代码如下:

// 单个音频子组件
const AudioItem = ({ song }) => {
  const [current, setCurrent] = useState("00:00");
  const [dur, setDur] = useState("00:00");
  const [bar, setBar] = useState("0%");

  // 格式化时间为MM:SS格式
  const formatTime = (seconds) => {
    if (isNaN(seconds)) return "00:00";
    const mins = Math.floor(seconds / 60);
    const secs = Math.floor(seconds % 60);
    return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
  };

  const playPause = () => {
    const audio = document.getElementById(`audio-${song.id}`);
    audio.paused ? audio.play() : audio.pause();
  };

  const timeUpdate = () => {
    const audio = document.getElementById(`audio-${song.id}`);
    if (!audio.duration) return;
    const rawdur = audio.duration;
    const curTime = audio.currentTime;
    setCurrent(formatTime(curTime));
    setDur(formatTime(rawdur));
    // 计算进度条百分比
    const progress = (curTime / rawdur) * 100;
    setBar(progress);
  };

  const skip = (event) => {
    const audio = document.getElementById(`audio-${song.id}`);
    const barPosition = event.currentTarget;
    const clickX = event.clientX - barPosition.getBoundingClientRect().left;
    const percent = clickX / barPosition.offsetWidth;
    audio.currentTime = percent * audio.duration;
  };

  return (
    <div className="audio-container">
      <h3>{song.title}</h3>
      <h5>{song.artist}</h5>
      <div className="audio-progress">
        <div className="current">{current}</div>
        <div className="length">{dur}</div>
        <div className="bar-postion" onClick={skip}>
          <div className="audio-bar" style={{ width: `${bar}%` }}></div>
        </div>
      </div>
      <audio
        id={`audio-${song.id}`}
        src={song.src}
        onTimeUpdate={timeUpdate}
      ></audio>
      {/* 添加播放暂停按钮,方便操作 */}
      <button onClick={playPause}>播放/暂停</button>
    </div>
  );
};

// 父组件
const Audio = () => {
  const songs = {
    song: [
      {
        id: 1,
        src: "http://192.168.1.15:4000/video/audio.mp3",
        title: "La calin",
        artist: "Sernath Drums"
      },
      {
        id: 2,
        src: "http://192.168.1.15:4000/video/audio2.mp3",
        title: "Ek Raat",
        artist: "Dark Music Production"
      }
    ]
  };

  return (
    <div className='body'>
      {songs.song.map((song) => (
        <AudioItem key={song.id} song={song} />
      ))}
    </div>
  );
};

export default Audio;

关键改动说明

  • 状态私有化:每个AudioItem拥有自己的current、dur、bar状态,更新时只会影响自身
  • 时间格式化:新增formatTime函数,把原始秒数转为用户友好的MM:SS格式
  • 绑定音频事件:给<audio>标签添加onTimeUpdate事件,自动触发时间更新逻辑,无需手动调用
  • 独立DOM选择器:音频ID加上前缀audio-,避免ID冲突(虽然原ID是唯一的,但更规范)

内容的提问来源于stack exchange,提问作者aman patel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 16:36:43