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

React.js冥想APP:点击新按钮时停止旧音频的实现求助

解决React冥想APP多音频同时播放的问题

你的核心问题在于单个playing状态无法区分不同音频的播放状态,同时混用了原生Audio对象和ReactPlayer,导致播放控制逻辑混乱。下面是具体的修复方案:

关键改动思路

  • 用currentPlayingId替代单个playing状态,记录当前正在播放的音频ID(无播放时为null)
  • 统一使用ReactPlayer管理音频,移除原生Audio实例,避免双重控制逻辑冲突
  • 点击按钮时,先停止之前播放的音频,再启动当前音频,同步更新状态

修改后的完整代码

import PropTypes from "prop-types";
import { useState, useRef } from "react";
import ReactPlayer from "react-player";

function Buttons({ soundsColor }) {
  const [currentPlayingId, setCurrentPlayingId] = useState(null);
  // 存储所有ReactPlayer实例,方便精准控制播放/暂停
  const playerRefs = useRef({});

  function handleSoundToggle(soundId) {
    // 点击正在播放的音频,直接暂停并清空状态
    if (currentPlayingId === soundId) {
      playerRefs.current[soundId]?.pause();
      setCurrentPlayingId(null);
      return;
    }

    // 暂停之前正在播放的音频
    if (currentPlayingId !== null) {
      playerRefs.current[currentPlayingId]?.pause();
    }

    // 播放当前音频并更新状态
    playerRefs.current[soundId]?.play();
    setCurrentPlayingId(soundId);
  }

  return (
    <>
      {soundsColor.map(({ name, color, description, soundUrl, id }) => (
        <button
          id={`btn-${id}`}
          className="p-20 relative rounded-[10px] active:scale-[0.98] transition-all 150ms ease-in"
          style={{ backgroundColor: color }}
          key={id}
          onClick={() => handleSoundToggle(id)}
        >
          <ReactPlayer
            url={soundUrl}
            ref={(player) => (playerRefs.current[id] = player)}
            width="100%"
            height="100%"
            // 隐藏默认控件,用自定义按钮控制播放
            controls={false}
            muted={false}
          />
          <div className="absolute top-20 w-3/4 left-3 text-left">
            <p className="text-[#000] font-bold font-sourceSans">{name}</p>
            <small className="font-sourceSans text-secondSubtext font-light">
              {currentPlayingId === id ? "Playing..." : description}
            </small>
          </div>
        </button>
      ))}
    </>
  );
}

Buttons.propTypes = {
  soundsColor: PropTypes.arrayOf(
    PropTypes.shape({
      id: PropTypes.number,
      name: PropTypes.string,
      description: PropTypes.string,
      color: PropTypes.string,
      soundUrl: PropTypes.string,
    })
  ),
};

export function SoundScapes() {
  const soundsColor = [
    {
      id: 0,
      name: "Suikinkutsu",
      color: "#daff6f",
      description: "Water Drip Resonance",
      soundUrl: "assets/Suikinkutsu.mp3",
    },
    {
      id: 1,
      name: "Cicadas",
      color: "#A8AEEF",
      description: "Insect Chorus",
      soundUrl: "./assets/Cicadas.mp3",
    },
    {
      id: 2,
      name: "Temple Bells",
      color: "#A8AEEF",
      description: "Waterfall Roar",
      soundUrl: "./assets/TempleBellSound.mp3",
    },
    {
      id: 3,
      name: "Shomyo Falls",
      color: "#daff6f",
      description: "Bell Resonance",
      soundUrl: "./assets/Waterfall.mp3",
    },
  ];

  return (
    <div className="grid grid-cols-2 grid-rows-2 gap-3 p-6 mt-8">
      <Buttons soundsColor={soundsColor} />
    </div>
  );
}

核心改动说明

  1. 状态管理优化:
    • 用currentPlayingId精准标记当前活跃音频,替代原有的全局playing布尔值,解决多音频状态冲突问题
  2. 实例化控制:
    • 通过useRef创建playerRefs对象,存储每个ReactPlayer实例,实现对指定音频的直接播放/暂停控制
  3. 播放逻辑统一:
    • 移除原生Audio对象,所有音频由ReactPlayer统一管理,避免双重控制逻辑混乱
    • 点击按钮时先判断是否为当前播放音频:是则暂停;否则先停掉之前的音频再播放当前的
  4. UI文本同步:
    • 基于currentPlayingId判断是否显示"Playing...",逻辑更清晰直观

修改后,点击不同按钮时,之前的音频会自动停止,同一时间仅会有一个音频播放,完全满足你的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 04:10:05