音频事件在通过removeEventListener删除后仍会触发事件

时间:2016-02-25 19:23:58

标签: javascript javascript-events reactjs html5-audio

我的React组件中有以下两个生命周期方法,这是一个包含HTML <audio>元素的音轨:

componentDidMount() {
  const {track} = this.props;

  this.refs.audio.src = track.getTrackUrl();
  _.each(this.audioEvents, (callback, eventName) => {
    this.refs.audio.addEventListener(eventName, callback.bind(this));
  });
}

componentWillUnmount() {
  _.each(this.audioEvents, (callback, eventName) => {
    console.info(`Removed ${eventName} from ${this.props.track.name}`);
    this.refs.audio.removeEventListener(eventName, callback.bind(this));
  });
}

我可以从console.info调用中看到所有事件都被删除了,但在导航离开此特定路径/页面时仍然会出现以下错误:

  

警告:setState(...):只能更新已安装或安装的组件。这通常意味着您在已卸载的组件上调用了setState()。这是一个无操作。请检查未定义组件的代码。

这种情况正在发生,因为即使我已经删除了所有事件处理程序,pause回调仍然被解雇了:

pause() {
  console.log('pause got fired for', this.props.track.name);
  this.setState({playing: false});
},

我错过了什么?当组件卸载时,我试图做一个很好的清理,但出于某种原因,当我离开页面时(导致音频停止播放),pause的事件处理程序仍然会触发。

1 个答案:

答案 0 :(得分:3)

使用.bind时,您可以创建该函数的新实例。所以当你这样做时:

this.refs.audio.addEventListener(eventName, callback.bind(this));

您将无法再删除该事件监听器,因为您没有抓住对callback.bind(this)的引用。以下是解决问题的方法。

componentDidMount() {
  const {track} = this.props;
  this.refs.audio.src = track.getTrackUrl();
  this.boundAudioEvents = _.mapValues(this.audioEvents, (callback, eventName) => {
    const boundEvent = callback.bind(this)
    this.refs.audio.addEventListener(eventName, boundEvent);
    return boundEvent;
  });
}

componentWillUnmount() {
  _.each(this.boundAudioEvents, (callback, eventName) => {
    console.info(`Removed ${eventName} from ${this.props.track.name}`);
    this.refs.audio.removeEventListener(eventName, callback);
  });
}