【问题标题】:React: Pass global keydown event listener down to mapped componentsReact:将全局 keydown 事件侦听器向下传递给映射的组件
【发布时间】:2024-04-12 02:15:02
【问题描述】:

我正在构建一个鼓机,我希望允许用户通过键盘输入与行为的按钮进行交互。这些按钮是通过从包含在 react 应用程序中成为道具的对象数组中映射出道具来呈现的。目前,容器组件中有一个 state 属性会发生变化,显示按下了哪个键盘键。如何将该状态属性(或事件信息)从容器组件传递到映射组件到映射组件,以及如何获得正确的按钮来播放?

代码如下:

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 中的挂载/卸载模式,并且我尝试了无数种方法来尝试将事件处理程序有条件地路由到正确的按钮。在所有这些尝试中,我得到的最好的结果是在使用键盘上的所有键首次单击按钮后播放声音(任何键盘键都会播放与最初单击相同的声音)。同样,如何将容器组件中的事件处理程序路由到正确的映射按钮组件?

【问题讨论】:

    标签: javascript reactjs event-handling


    【解决方案1】:

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

    【讨论】:

      最近更新 更多