首页 > 解决方案 > 无法读取未定义的“键”的属性,在 React 中处理事件

问题描述

我的目标是拥有一个运行 Javascript 的按钮,roshtimer()并且还有可用于运行命令的热键。例如,我希望我的用户可以选择单击屏幕上的按钮或按键盘上的“r”。

我在这个问题上遇到了很多麻烦,因为我对 React 还比较陌生。

class Timer extends Component {
  constructor(props) {
    super(props);
    this.state = {
      time: 0,
      roshDead: false,
      roshDeathTime: 0,
      aegisExpireTime: 0,
      roshRespawnTime1: 0,
      roshRespawnTime2: 0,
      start: 0,
      isOn: false,
    };
    this.startTimer = this.startTimer.bind(this);
    this.stopTimer = this.stopTimer.bind(this);
    this.resetTimer = this.resetTimer.bind(this);
    this.roshTimer = this.roshTimer.bind(this);
    this.roshButton = React.createRef();
    this.handleRoshHotkey = this.handleRoshHotkey.bind(this);
  }
  componentDidMount() {
    document.addEventListener("keydown", this.handleRoshHotkey);
  }
  componentWillUnmount() {
    document.removeEventListener("keydown", this.handleRoshHotkey);
  }

  handleRoshClick() {
    console.log("button was clicked!");
    this.roshTimer();
  }
  handleRoshHotkey = (e) => {
    if (e.key === "r" || e.keyCode === 13) {
      console.log("hotkey was pressed!");
      this.roshTimer();
    }
  };
  startTimer() {
    ...
  }
  stopTimer() {
    ...
  }
  resetTimer() {
    ...
  }
  roshTimer() {
    //compute rosh timers

    let roshDeathTime = this.state.time;
    let newAegisExpire = this.state.time + 300000; //5 mins = 300000 milliseconds
    let newRespTime1 = this.state.time + 480000; // 8 mins = 480000 milliseconds
    let newRespTime2 = this.state.time + 660000; // 11 mins = 660000 milliseconds

    this.setState({
      roshDeathTime: this.state.time,
      aegisExpireTime: newAegisExpire,
      roshRespawnTime1: newRespTime1,
      roshRespawnTime2: newRespTime2,
      roshDead: true,
    });

    //format rosh timers
    ...

    //log to console for my own sanity
    console.log(roshDeathTime, newAegisExpire, newRespTime1, newRespTime2);
    //copy to user's clipboard
    navigator.clipboard.writeText(
      newAegisExpire + " " + newRespTime1 + " " + newRespTime2
    );
  }
  render() {
    let start =
      this.state.time == 0 ? (
        <button onClick={this.startTimer}>start</button>
      ) : null;
    let stop = this.state.isOn ? (
      <button onClick={this.stopTimer}>stop</button>
    ) : null;
    let reset =
      this.state.time != 0 && !this.state.isOn ? (
        <button class="red" onClick={this.resetTimer}>
          reset
        </button>
      ) : null;
    let resume =
      this.state.time != 0 && !this.state.isOn ? (
        <button class="green" onClick={this.startTimer}>
          resume
        </button>
      ) : null;
    let rosh = this.state.isOn ? (
      <div className={this.state.focused ? "focused" : ""}>
        <button
          onClick={() => this.handleRoshClick()}
          autoFocus
          ref={(c) => (this._input = c)}
        >
          {" "}
          Rosh died!{" "}
        </button>
      </div>
    ) : null;

    return (
      <div>
        <h3>
          Timer: {prettyMilliseconds(this.state.time, { colonNotation: true })}
        </h3>
        {start}
        {resume}
        {stop}
        {reset}
        <div ref={this.roshButton} autofocus onKeyDown={() => this.handleRoshHotkey()} tabIndex={1}>
          {rosh}
        </div>
      </div>
    );
  }
}

export default Timer;

目前,我可以运行我的应用程序并发送垃圾邮件“Rosh 死了!” 按钮并查看预期的输出。如果我点击网页上的任何地方,我就可以使用热键来获得预期的输出。但是,如果我在手动单击按钮之前使用热键,应用程序会崩溃,我会收到欢迎

TypeError: Cannot read property 'key' of undefined

进一步说明我的问题在这里:

  handleRoshHotkey = (e) => {
    if (e.key === "r" || e.keyCode === 13){ <-------------
      console.log("hotkey was pressed!");
      this.roshTimer();
    }
  };

这是一个示例控制台日志,直到它崩溃:

button was clicked!
1134 "5:01" "8:01" "11:01"
button was clicked!
1878 "5:01" "8:01" "11:01"
hotkey as pressed!
4318 "5:04" "8:04" "11:04"
hotkey was pressed!
5338 "5:05" "8:05" "11:05"
button was clicked!
 8142 "5:08" "8:08" "11:08"
Uncaught TypeError: Cannot read property 'key' of undefined
.
. //(hundreds of lines of traceback follow)
. 
hotkey was pressed!
11194 "5:11" "8:11" "11:11"

谢谢!

标签: javascriptreactjsevent-handling

解决方案


两件事情:

  1. 主要问题是当你渲染时,你正在做

    onKeyDown={() => this.handleRoshHotkey()}
    

    ...它handleRoshHotkey没有参数调用,这就是你得到错误的原因。由于您已bind在构造函数中使用,请将其更改为:

    onKeyDown={this.handleRoshHotkey}
    
  2. 在 React 中使用处理程序就足够了,您不想通过 使用它addEventListener,因此删除该代码(我猜您添加它是为了调试)。您可以完全删除componentDidMountand componentWillUnmount


推荐阅读