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 に答える