如何用React+TypeScript实现鼓机?现有代码报错求助
问题分析与修复方案
你的代码存在几个关键问题导致声音无法播放,以下是逐一修复思路及最终代码:
核心问题点
- 参数传递错误:点击按钮和键盘触发时,你传入
handlePlay的是声音名称(如"Kick"),但实际需要传入音频资源路径;同时显示区域应该展示声音名称而非资源路径。 - Howl配置错误:Howl构造函数的
src参数要求为数组类型,你传入的单个字符串会导致音频加载失败。 - 重复创建实例浪费资源:每次播放都新建Howl实例,建议提前初始化所有声音实例,提升性能。
- TypeScript类型缺失:未定义sound对象的明确类型,使用
any会降低代码健壮性。
修复后的完整代码
import { useState, useEffect } from "react"; import "./App.css"; import kick from "./assets/kick.mp3"; import snare from "./assets/snare.mp3"; import hiHat from "./assets/hi-hat.mp3"; import tom from "./assets/tom.mp3"; import clap from "./assets/clap.mp3"; import shaker from "./assets/shaker.mp3"; import tambourine from "./assets/tambourine.mp3"; import cymbal from "./assets/cymbal.mp3"; import cowbell from "./assets/cowbell.mp3"; import { Howl, Howler } from "howler"; // 定义Sound对象的TypeScript类型 type Sound = { key: string; name: string; src: string; soundInstance?: Howl; }; const sounds: Sound[] = [ { key: "Q", name: "Kick", src: kick }, { key: "W", name: "Snare", src: snare }, { key: "E", name: "Hi-hat", src: hiHat }, { key: "A", name: "Tom", src: tom }, { key: "S", name: "Clap", src: clap }, { key: "D", name: "Shaker", src: shaker }, { key: "Z", name: "Tambourine", src: tambourine }, { key: "X", name: "Cymbal", src: cymbal }, { key: "C", name: "Cowbell", src: cowbell }, ]; function App() { const [display, setDisplay] = useState(""); // 初始化所有Howl实例,仅在组件挂载时执行一次 useEffect(() => { sounds.forEach(sound => { sound.soundInstance = new Howl({ src: [sound.src] // src必须传入数组格式 }); }); Howler.volume(1.0); }, []); const handlePlay = (sound: Sound) => { setDisplay(sound.name); sound.soundInstance?.play(); }; const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => { const sound = sounds.find((s) => s.key === event.key.toUpperCase()); if (sound) handlePlay(sound); }; return ( <div id="drum-machine" onKeyDown={handleKeyDown} tabIndex={0}> <div id="display">{display}</div> <div id="pad-container"> {sounds.map((sound) => ( <button className="drum-pad" id={sound.name} key={sound.key} onClick={() => handlePlay(sound)} > {sound.key} </button> ))} </div> </div> ); } export default App;
原生audio标签方案补充
如果你想改用原生<audio>标签实现,需要为每个标签绑定src并通过ref控制播放,示例片段:
// 组件内定义ref集合 const audioRefs = useRef<Record<string, HTMLAudioElement | null>>({}); // 播放函数 const handlePlay = (sound: Sound) => { setDisplay(sound.name); audioRefs.current[sound.key]?.play(); }; // 按钮内的audio标签 <audio ref={el => audioRefs.current[sound.key] = el} id={sound.key} src={sound.src} />
内容的提问来源于stack exchange,提问作者Wallace Nascimento
相关产品推荐
相关产品推荐

