1

我即将为钢琴建立一个键盘,我想使用状态来处理按下和未按下的键(最终产生声音的键,以便我可以弹奏单个音符和和弦)

我通过以下方式修改了一个在线教程:首先我创建了这些对象:

export const NOTES = [
  { name: "c", accid: "natural", hz: 3270, keyboard: "q" },
  { name: "d", accid: "flat", hz: 3465, keyboard: "2" },
  { name: "d", accid: "natural", hz: 3671, keyboard: "w" },
  { name: "e", accid: "flat", hz: 3889, keyboard: "3" },
  { name: "e", accid: "natural", hz: 4120, keyboard: "e" },
  { name: "f", accid: "natural", hz: 4365, keyboard: "r" },
  { name: "g", accid: "flat", hz: 4625, keyboard: "5" },
  { name: "g", accid: "natural", hz: 4900, keyboard: "t" },
  { name: "a", accid: "flat", hz: 5191, keyboard: "6" },
  { name: "a", accid: "natural", hz: 5500, keyboard: "z" },
  { name: "b", accid: "flat", hz: 5827, keyboard: "7" },
  { name: "b", accid: "natural", hz: 6174, keyboard: "u" },
];

我的第一步是将按下的键盘键加载到连接到全局状态对象的数组中。稍后我想为该状态数组中表示的键盘键表示的所有对象创建声音。但首先要做的事情。

当我按下一个键时,为什么this.state.pressedKeys(扩展运算符)未定义?

TypeError:无法读取未定义的属性“pressedKeys”

import React from "react";
import Key from "./Key";
import "./Piano.css";
import { NOTES } from "../global/constants";

class Piano extends React.Component {
  constructor(props) {
    super(props);
    this.state = { pressedKeys: [] };
  }

  componentDidMount = () => {
    window.addEventListener("keydown", this.handleKeyDown);
  //  window.addEventListener("keyup", this.handleKeyUp);
  };

  handleKeyDown(event) {
    if (event.repeat) {
      return;
    }

    const key = event.key;
    const updatedPressedKeys = [...this.state.pressedKeys];
    if (!updatedPressedKeys.includes(key)) {
      updatedPressedKeys.push(key);
    }

    this.setState({
      pressedKeys: updatedPressedKeys,
    });
  }

  render() {
    const keys = NOTES.map((note) => {
      return (
        <Key
          key={note.hz}
          note={note.name}
          accid={note.accid}
          pressedKeys={this.state.pressedKeys}
        />
      );
    });

    return <div className="piano">{keys}</div>;
  }
}

export default Piano;
4

1 回答 1

2

您错过了this将类组件的绑定到handleKeyDown回调,因此this没有引用该组件。这导致在this.state回调中未定义。

按优先顺序:

  1. 您可以使用箭头功能进行绑定。

    handleKeyDown = event => { .... }
    
  2. 您可以在构造函数中绑定。

    constructor(props) {
      super(props);
      this.state = { pressedKeys: [] };
    
      this.handleKeyDown = this.handleKeyDown.bind(this);
    }
    
  3. 您可以在附加/传递道具时绑定。

    window.addEventListener("keydown", this.handleKeyDown.bind(this));
    

我建议还使用功能状态更新来计算是否包含密钥,并在必要时创建下一个状态。

handleKeyDown = event => {
  if (event.repeat) {
    return;
  }

  const { key } = event;

  this.setState(prevState => {
    if (prevState.pressedKeys.includes(key)) {
      return prevState;
    }
    return {
      pressedKeys: [...prevState.pressedKeys, key],
    }
  });
}
于 2021-08-12T23:24:41.810 回答