反应:向下传递全局keydown事件侦听器到映射的组件

时间:2019-07-25 03:25:28

标签: javascript reactjs event-handling

我正在制造鼓机,我希望允许用户通过键盘输入与操作按钮进行交互。这些按钮是通过从对象数组中映射出props来渲染的,这些对象包含react应用程序中变为props的对象。当前,容器组件中有一个状态属性会更改,该属性显示按下了哪个键盘键。如何将状态属性(或事件信息)传递给从容器组件到映射组件的映射组件,以及如何获得正确的按钮播放?

代码如下:

Container.js

class Container extends React.Component {
  constructor(props) {
    super(props);

    this.handlePowerState = this.handlePowerState.bind(this);
    this.state = {
      sound: "press a button!",
      powered: true,
      lastPressedKey: null
    };
  }

  componentDidMount() {
    document.addEventListener("keydown", this.handleKeyPress);
  }

  componentWillUnmount() {
    document.removeEventListener("keydown", this.handleKeyPress);
  }

  handleKeyPress = event => {
    console.log(event.key);

    this.setState({ lastPressedKey: event.key });
  };

  /*   keyboardPlaySound = e => {
    console.log(e.key);
    console.log(this.state.lastKeyPressed);
    if (this.props.keyPressed === this.props.keyLetter) {
      this.props.isPowered && this.audio.play();
      this.audio.currentTime = 0;
    }
  }; */

  logTheSound = clipName => {
    this.setState({
      sound: clipName
    });
    //console.log(this.state.sound);
  };

  handlePowerState() {
    this.setState({
      powered: !this.state.powered
    });
  }

  componentDidUpdate() {
    document.addEventListener("keydown", this.keyboardPlaySound);
  }

  render() {
    const ButtonComponents = SoundData.map(button => (
      <SoundButton
        //onClick={this.playSound}
        key={button.keyLetter}
        lastPressedKey={event => this.state.lastPressedKey(event)}
        onKeyDown={this.handleKeypress}
        isPowered={this.state.powered}
        keyLetter={button.keyLetter}
        button={button.togglePlay}
        clipSrc={button.clipSrc}
        clipName={button.clipName}
        //clip={this.state.sound}
        logSound={this.logTheSound}
        tabIndexValue={this.tabIndexValue}
      >
        {button.clipName} {button.key}
      </SoundButton>
    ));
    return (
      <div className="machine-container">
        <main className="button-container">{ButtonComponents}</main>
        <div className="mutation-container">
          <PowerSwitch
            isPowered={this.state.powered}
            onChange={this.handlePowerState}
          />
        </div>
      </div>
    );
  }
}

export default Container;

SoundButton.js

class SoundButton extends React.Component {
  audio = new Audio(this.props.clipSrc);
  //console.log(this.mappedSoundObjects);

  playSound = event => {
    this.props.isPowered && this.audio.play();
    this.audio.currentTime = 0;

    //console.log(this.props.clipName);
  };

  keyboardPlaySound = e => {
    //console.log(e.key);
    console.log(this.props.onKeyDown);
    this.props.isPowered && this.audio.play();
    this.audio.currentTime = 0;
  };

  render() {
    return (
      <button
        //style={buttonBottoms}
        isPowered={this.props.isPowered}
        onClick={event => {
          this.playSound();
          this.props.logSound(this.props.clipName);
        }}
        //onKeyDown={this.handleKeyPress}
        onKeyDown={event => {
          this.keyboardPlaySound();
          this.props.logSound(this.props.clipName);
        }}
        tabIndex={this.tabIndexValue}
        //className="clip myButton ui button"
        className="buttons"
      >
        {this.props.keyLetter}
      </button>
    );
  }
}

export default SoundButton;

如代码中所示,我正在使用here所示的mount / Unmount模式,并且我尝试了无数种方法来尝试将事件处理程序有条件地路由到正确的按钮。在所有这些尝试中,我最好的方法是使用键盘上的所有键在首次单击按钮后播放声音(任何键盘键都将播放与最初单击时相同的声音)。同样,如何将容器组件中的事件处理程序路由到正确的映射按钮组件?

1 个答案:

答案 0 :(得分:1)

也许您应该考虑组件之间的某种通知。 看一看:它显示了组件的实现,该组件发送可以订阅的消息。 https://jasonwatmore.com/post/2019/02/13/react-rxjs-communicating-between-components-with-observable-subject