在Reaction中将函数传递给无状态功能组件时出现问题

11dmarpk  于 2022-10-15  发布在  React
关注(0)|答案(1)|浏览(169)

我正在为一个免费的CodeCamp项目在Reaction中创建一台鼓机。我已经渲染了按钮,但无法获得播放音频的按钮。
我已经创建了一个无状态的功能组件,它遍历包含音频url和其他一些细节的对象数组,创建了一个键盘来播放声音。播放音频的函数在应用程序组件中,我将该函数作为道具传递给键盘。
我在控制台中收到一个对象错误,并且不知道它来自哪里。CodePen在这里(https://codepen.io/cpmcclure/pen/qBXGNpw),我也复制了下面的代码。任何想法都会有所帮助。提前谢谢!

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>
dm7nw8vv

dm7nw8vv1#

似乎有一个命名错误:组件函数是const Keyboard = ({playSound}) => {,但它是用<Keyboard play={this.playSound}/>创建的。正确的匹配应该是<Keyboard playSound={this.playSound}/>
此外,class应该是className,并且所有数组子元素都需要有唯一的键。
我建议在整个过程中使用功能组件。不需要任何状态,如果需要,您可以使用useState挂钩。
我建议将音频对象附加到您的鼓套件元素上。将工具包数据保持在自己的数据结构中可以减轻组件呈现<audio>元素,然后根据id查找它们只是为了播放剪辑的负担。在设置了kit[i] = new Audio(kit[i].url)之后,不需要查看DOM--相反,您可以简单地说kit[i].audio.play()(kit是一个通用工具包,我们在这里设置了TR66)。
如果需要,您可以将文档监听器用于关键触发器,或将该监听器单独连接到鼓机组件。这说明,将音频对象放在工具包中使得从多个地方播放它们变得很容易,尽管我意识到它在您当前的代码中有点超前。如果您不需要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.createRoot(document.querySelector("#app"))
  .render(<App />);
button {
  width: 5rem;
  height: 5rem;
}
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="app"></div>

相关问题