使用箭头函数表示法时“按键”事件被调用两次

'Keypress" event called twice when using arrow function notation

我希望每次按下该键时都会记录一次按下的每个键,但是每次按下时每个键都会记录两次。但是,仅当对传递给事件侦听器的函数使用箭头表示法时。

class Test extends React.Component {
  constructor(props) {
    super(props)
    window.addEventListener('keypress', (e) => this.KeyPress(e)) //works fine with this.KeyPress
  }
  
  KeyPress(e){
  console.log(e.key)
  }
  
  render() {
    return (
      <div>
        <h1>hi there</h1>
      </div>
    )
  }
}

令人困惑的是,此代码在 jsfiddle 上按预期工作: https://jsfiddle.net/wgqs75pr/4/ 但是,它在全新的 create-react-app 上无法按预期工作。

为什么每次 KeyPress 都会调用两次 this.KeyPress?

对我来说,仍然使用 class 组件没有意义,它们不适合更大的组件。

如果是因为您遵循了具有 statelessstate 组件的旧指南,则在 React hooks 发布时此模式已被弃用宣布。我建议您研究一下钩子如何解决像这样的许多烦人的错误。

无论如何,我建议你把它放在生命周期方法中。你可以在这里阅读更多关于它们的信息: https://reactjs.org/docs/react-component.html#render

请检查代码,我还在组件卸载时添加了 removeEventListener。

class Test extends React.Component {
  constructor(props) {
    super(props)
  }
  
  componentDidMount() {
    window.addEventListener('keypress', (e) => this.KeyPress(e))
  }
  
  componentWillUnmount() {
    window.removeEventListener('keypress', (e) => this.KeyPress(e))
  }
  
  KeyPress(e){
    console.log(e.key)
  }
  
  render() {
    return (
      <div>
        <h1>hi there</h1>
      </div>
    )
  }
}

ReactDOM.render(<Test />, document.querySelector("#app"))

ReactDOM.render(<Test />, document.querySelector("#app"))

每个键是键被记录两次的原因是因为 keypress 有两个事件处理程序。这很可能是因为 React 在 strict mode 中是 运行,所以构造函数被调用了两次。这也是代码在 jsfiddle 上运行良好的原因,因为在生产模式下禁用了严格模式。

要解决此问题,请在 componentDidMount 生命周期函数中附加事件处理程序:

class Test extends React.Component {
  constructor(props) {
    super(props)
  }
  
  KeyPress(e){
    console.log(e.key)
  }
  
  componentDidMount() {
    window.addEventListener('keypress', (e) => this.keyPress(e))
  }
  
  render() {
    return (
      <div>
        <h1>hi there</h1>
      </div>
    )
  }
}

删除 componentWillUnmount 中的事件侦听器可能也很有用,否则您可能会遇到意外行为。