在IE11中删除后调用的事件侦听器函数

时间:2017-01-31 14:04:09

标签: javascript reactjs

我一直在构建组件,听取整个文档的点击,并偶然发现IE11问题。

我写了几个简单的组件来重现这个问题。

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

    this.state = {
      show: false
    }
  }

  render() {
    return ( 
      <div>
        <button 
          onClick={() => this.setState({
              show: !this.state.show
          })}
        >
          Toggle
        </button>
        
        <div>
          {this.state.show && (
            <Component />
          )} 
        </div>
      </div>
    )
  }
}

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

    this.handleClick = this.handleClick.bind(this);
  }

  componentDidMount() {
    console.log('listener added')
    document.addEventListener('click', this.handleClick)
  }

  componentWillUnmount() {
    console.log('listener removed')
    document.removeEventListener('click', this.handleClick)
  }

  handleClick() {
    console.log('clicked!');
    const node = ReactDOM.findDOMNode(this);
  }

  render() {
    return <div>Component</div>
  }
}


ReactDOM.render(
  <App /> ,
  document.getElementById('container')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="container"></div>

因此,Component组件会将click侦听器添加到文档中,App组件负责安装和卸载Component

当应用了Component挂载事件监听器以及取消挂载侦听器时,Chrome和Firefox中的所有功能都非常完美。

但是,在IE11中,当删除侦听器时,仍然会调用处理程序函数并抛出错误,因为它会尝试findDOMNode未安装的组件。这可能不是一个突破性问题,但它仍然让我烦恼,我想知道是否有任何解决方法。

此外,注意 - 通过event.stopPropagation停止传播不是一种选择,因为在我的应用Component中可以通过多种方式卸载,按钮点击只是一个示例

JSFiddle reproducing the issue

1 个答案:

答案 0 :(得分:0)

这似乎是IE11中的一个错误。一些选择:

1

使用window.addEventListener/window.removeEventListenerdocument.addEventListener/document.removeEventListener应该有效。

2

我已经看到其他解决方案用isMounted包裹处理程序:

if (this.isMounted) {
    const node = ReactDOM.findDOMNode(this);
}

但不推荐isMounted并发出警告。 It is considered an antipattern

3

当前 hack 将创建您自己的isMounted。类似的东西:

componentDidMount() {
    this.mounted = true;
    document.addEventListener('click', this.handleClick)
}

componentWillUnmount() {
    this.mounted = false;
    document.removeEventListener('click', this.handleClick)
}

handleClick() {
    if (this.mounted) {
        const node = ReactDOM.findDOMNode(this);
    }
}

但这只会绕过isMounted控制台警告。