简体   繁体   English

将 function 传递给 React 中的无状态功能组件时遇到问题

[英]Trouble passing a function to a stateless functional component in React

I'm creating a drum machine in React for a freeCodeCamp project.我正在为一个 freeCodeCamp 项目在 React 中创建一个鼓机。 I have the buttons rendered, but cannot get the buttons to play the audio.我渲染了按钮,但无法获得播放音频的按钮。

I've created a stateless functional component that iterates through an array of objects containing the the audio url and a few other details, creating a keyboard to play the sounds.我创建了一个无状态功能组件,它遍历包含音频 url 和其他一些细节的对象数组,创建一个键盘来播放声音。 The function to play the audio is in the app component, and I'm passing the function to the Keyboard as props.播放音频的 function 在应用程序组件中,我将 function 作为道具传递给键盘。

I'm getting an object error in the console, and can't figure out where it's coming from.我在控制台中收到 object 错误,无法弄清楚它来自哪里。 The CodePen is here ( https://codepen.io/cpmcclure/pen/qBXGNpw ), and I've copied the code below as well. CodePen 在这里( https://codepen.io/cpmcclure/pen/qBXGNpw ),我也复制了下面的代码。 Any thoughts would help.任何想法都会有所帮助。 Thanks in advance!提前致谢!

 class App extends React.Component { constructor(props) { super(props); this.playSound = this.playSound.bind(this); } playSound = (key) => { const audio = document.getElementById(key); audio.currentTime = 0; audio.play(); } render() { return( <Keyboard play={this.playSound}/> ) } } const Keyboard = ({playSound}) => { return TR66.map(sound => { return (<button class="drum-pad" id={sound.id} onClick={() => playSound(sound.key)}> <audio class="clip" id={sound.key} src={sound.url}/> <div>{sound.key}</div> </button>) }); } const TR66 = [ { keyCode: 81, key: 'Q', id: 'Bass Drum', url: 'https://sampleswap.org/samples-ghost/DRUMS%20(FULL%20KITS)/DRUM%20MACHINES/Roland%20TR-66/15[kb]66-bd-01.wav.mp3' }, { keyCode: 87, key: 'W', id: 'Snare', url: 'https://sampleswap.org/samples-ghost/DRUMS%20(FULL%20KITS)/DRUM%20MACHINES/Roland%20TR-66/14[kb]66-sd-01.wav.mp3' }, { keyCode: 69, key: 'E', id: 'Hi Hat 1', url: 'https://sampleswap.org/samples-ghost/DRUMS%20(FULL%20KITS)/DRUM%20MACHINES/Roland%20TR-66/6[kb]66-hh-01-or.wav.mp3' }, { keyCode: 65, key: 'A', id: 'Hi Hat 2', url: 'https://sampleswap.org/samples-ghost/DRUMS%20(FULL%20KITS)/DRUM%20MACHINES/Roland%20TR-66/5[kb]66-hh-08.wav.mp3' }, { keyCode: 83, key: 'S', id: 'Hi Hat Open 1', url: 'https://sampleswap.org/samples-ghost/DRUMS%20(FULL%20KITS)/DRUM%20MACHINES/Roland%20TR-66/33[kb]66-hho-01-or.wav.mp3' }, { keyCode: 68, key: 'D', id: 'Hi Hat Open 2', url: 'https://sampleswap.org/samples-ghost/DRUMS%20(FULL%20KITS)/DRUM%20MACHINES/Roland%20TR-66/37[kb]66-hho-04.wav.mp3' }, { keyCode: 90, key: 'Z', id: 'Wood Block Low', url: 'https://sampleswap.org/samples-ghost/DRUMS%20(FULL%20KITS)/DRUM%20MACHINES/Roland%20TR-66/26[kb]66-per-08.wav.mp3' }, { keyCode: 88, key: 'X', id: 'Wood Block High', url: 'https://sampleswap.org/samples-ghost/DRUMS%20(FULL%20KITS)/DRUM%20MACHINES/Roland%20TR-66/12[kb]66-per-03.wav.mp3' }, { keyCode: 67, key: 'C', id: 'Rim', url: 'https://sampleswap.org/samples-ghost/DRUMS%20(FULL%20KITS)/DRUM%20MACHINES/Roland%20TR-66/11[kb]66-rim-01.wav.mp3' } ] ReactDOM.render(<App />, document.getElementById("drum-machine"))
 button { width: 5rem; height: 5rem; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script> <div id="drum-machine"> </div>

There appears to be a mistake in naming: the component function is const Keyboard = ({playSound}) => { but it's created with <Keyboard play={this.playSound}/> .命名似乎有误:组件 function 是const Keyboard = ({playSound}) => {但它是用<Keyboard play={this.playSound}/>创建的。 The correct match would be <Keyboard playSound={this.playSound}/> .正确的匹配是<Keyboard playSound={this.playSound}/>

Also, class should be className and all array child elements need to have unique keys.此外, class应该是className并且所有数组子元素都需要具有唯一键。

I suggest using functional components throughout.我建议始终使用功能组件。 No state is necessary, and if it was, you can use the useState hook .没有 state 是必需的,如果是,您可以使用useState挂钩

I recommend attaching the audio objects to your drum kit elements.我建议将音频对象附加到您的架子鼓元素。 Keeping the kit data self-contained in its own data structure alleviates the burden on your components of rendering <audio> elements, then subsequently finding them by id just to play a clip.将套件数据自包含在自己的数据结构中可以减轻渲染<audio>元素的组件的负担,然后通过 id 查找它们只是为了播放剪辑。 There's no need to go through the DOM -- instead, you can simply say kit[i].audio.play() ( kit is a generic kit that we fill with the TR66 set here) once you've set kit[i] = new Audio(kit[i].url) .没有必要通过 DOM 来 go —— 相反,你可以简单地说kit[i].audio.play()kit是一个通用套件,我们在这里用TR66设置填充)一旦你设置了kit[i] = new Audio(kit[i].url)

You can use a document listener for the key triggers, if desired, or attach that listener to the drum machine component alone.如果需要,您可以将文档侦听器用于键触发器,或者将该侦听器单独附加到鼓机组件。 This illustrates that having the audio objects in the kit makes it easy to play them from multiple places, although I realize it's jumping ahead a bit on your current code.这说明在套件中包含音频对象可以轻松地从多个位置播放它们,尽管我意识到它在您当前的代码上有点领先。 Remove the useEffect if you don't need this.如果不需要,请删除useEffect

 const App = () => <DrumMachine kit={TR66} />; const DrumPad = ({text, onPlay}) => ( <button className="drum-pad" onClick={onPlay}> <div>{text}</div> </button> ); const DrumMachine = ({kit}) => { const playAudio = audio => { audio.currentTime = 0; audio.play(); }; React.useEffect(() => { const listener = e => { const drum = kit.find(({key}) => key.toLowerCase() === e.key.toLowerCase() ); drum && playAudio(drum.audio); }; document.addEventListener("keydown", listener); return () => document.removeEventListener("keydown", listener); }, []); return ( <div> {kit.map(({key, id, audio}) => <DrumPad key={id} text={key} onPlay={() => playAudio(audio)} /> )} </div> ); }; const TR66 = [ { keyCode: 81, key: 'Q', id: 'Bass Drum', url: 'https://sampleswap.org/samples-ghost/DRUMS%20(FULL%20KITS)/DRUM%20MACHINES/Roland%20TR-66/15[kb]66-bd-01.wav.mp3' }, { keyCode: 87, key: 'W', id: 'Snare', url: 'https://sampleswap.org/samples-ghost/DRUMS%20(FULL%20KITS)/DRUM%20MACHINES/Roland%20TR-66/14[kb]66-sd-01.wav.mp3' }, { keyCode: 69, key: 'E', id: 'Hi Hat 1', url: 'https://sampleswap.org/samples-ghost/DRUMS%20(FULL%20KITS)/DRUM%20MACHINES/Roland%20TR-66/6[kb]66-hh-01-or.wav.mp3' }, { keyCode: 65, key: 'A', id: 'Hi Hat 2', url: 'https://sampleswap.org/samples-ghost/DRUMS%20(FULL%20KITS)/DRUM%20MACHINES/Roland%20TR-66/5[kb]66-hh-08.wav.mp3' }, { keyCode: 83, key: 'S', id: 'Hi Hat Open 1', url: 'https://sampleswap.org/samples-ghost/DRUMS%20(FULL%20KITS)/DRUM%20MACHINES/Roland%20TR-66/33[kb]66-hho-01-or.wav.mp3' }, { keyCode: 68, key: 'D', id: 'Hi Hat Open 2', url: 'https://sampleswap.org/samples-ghost/DRUMS%20(FULL%20KITS)/DRUM%20MACHINES/Roland%20TR-66/37[kb]66-hho-04.wav.mp3' }, { keyCode: 90, key: 'Z', id: 'Wood Block Low', url: 'https://sampleswap.org/samples-ghost/DRUMS%20(FULL%20KITS)/DRUM%20MACHINES/Roland%20TR-66/26[kb]66-per-08.wav.mp3' }, { keyCode: 88, key: 'X', id: 'Wood Block High', url: 'https://sampleswap.org/samples-ghost/DRUMS%20(FULL%20KITS)/DRUM%20MACHINES/Roland%20TR-66/12[kb]66-per-03.wav.mp3' }, { keyCode: 67, key: 'C', id: 'Rim', url: 'https://sampleswap.org/samples-ghost/DRUMS%20(FULL%20KITS)/DRUM%20MACHINES/Roland%20TR-66/11[kb]66-rim-01.wav.mp3' } ]; TR66.forEach(({url}, i) => { TR66[i].audio = new Audio(url); }); ReactDOM.render(<App />, document.getElementById("app"));
 button { width: 5rem; height: 5rem; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script> <div id="app"></div>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM