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> ); }
核心改动说明
- 状态管理优化:
- 用
currentPlayingId精准标记当前活跃音频,替代原有的全局playing布尔值,解决多音频状态冲突问题
- 用
- 实例化控制:
- 通过
useRef创建playerRefs对象,存储每个ReactPlayer实例,实现对指定音频的直接播放/暂停控制
- 通过
- 播放逻辑统一:
- 移除原生
Audio对象,所有音频由ReactPlayer统一管理,避免双重控制逻辑混乱 - 点击按钮时先判断是否为当前播放音频:是则暂停;否则先停掉之前的音频再播放当前的
- 移除原生
- UI文本同步:
- 基于
currentPlayingId判断是否显示"Playing...",逻辑更清晰直观
- 基于
修改后,点击不同按钮时,之前的音频会自动停止,同一时间仅会有一个音频播放,完全满足你的需求。
内容的提问来源于stack exchange,提问作者Matteo
相关产品推荐
相关产品推荐

