使用 react.js 创建钢琴,使用状态不明

creating a piano with react.js, use of state unclear

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

我按照以下方式修改了在线教程:首先我创建了这些对象:

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;

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

优先顺序:

  1. 您可以使用箭头函数进行绑定。

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

    constructor(props) {
      super(props);
      this.state = { pressedKeys: [] };
    
      this.handleKeyDown = this.handleKeyDown.bind(this);
    }
    
  3. 当attaching/passingprop.

    时可以绑定
    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],
    }
  });
}