如何在React.js中正确删除事件侦听器?

时间:2016-08-22 19:18:32

标签: reactjs

我在这里有点腌渍,我自己做了一个简单的组件,它可以异步加载图像并在准备好后显示它们。我的问题是我在某种程度上没有正确删除事件监听器,因为React抱怨它无法在未安装的组件上设置状态。

我的代码:

export default class Image extends React.Component {
  constructor() {
    super()
    this.state = {
      preloadReady: false,
      sourceReady: false,
      img1: new window.Image(),
      img2: new window.Image(),
    }
  }
  load() {
    let preload = this.refs.preloadElement,
        src = this.refs.completeElement,
        self = this, ctx1, ctx2, img1, img2, load;

        ctx1 = preload.getContext('2d');
        ctx2 = src.getContext('2d');

        this.state.img1.addEventListener('load', () => {
            load(this.state.img1, ctx1, preload)
            this.setState({preloadReady: true});
        })


        this.state.img1.crossOrigin = "anonymous";
        this.state.img1.src = this.props.preload;

        this.state.img2.crossOrigin = "anonymous";

        this.state.img2.addEventListener('load',
            () => {
                setTimeout( () => {load(this.state.img2, ctx2, src)
                this.setState({sourceReady: true});
            }, 100)
        })

        this.state.img2.src = this.props.src;

        load = function(img, ctx, canvas) {
            var data, filtered;

            canvas.width = img.width;
            canvas.height = img.height;
            ctx.drawImage(img ,0 ,0 ,img.width,img.height,0,0, canvas.width, canvas.height);

        }
  }
  componentDidMount() {
    this.load();
  }
  componentWillUnmount() {
    // The following does not work
    this.state.img1.removeEventListener('load');
    this.state.img2.removeEventListener('load');
  }
  render () {

    let classes = {
      src: '',
      pre: ''
    }

    if (this.state.preloadReady) classes.pre = 'ready';
    if (this.state.sourceReady) classes.src = 'ready';

    return (
      <div class="async-image tr_quick" style={{width: this.props.width, height: this.props.height}}>
          <canvas ref="preloadElement" style={{width: this.props.width, height: this.props.height}} class={'preload tr_quick ' + classes.pre}></canvas>
          <canvas ref="completeElement" style={{width: this.props.width, height: this.props.height}} class={'src tr_quick ' + classes.src}></canvas>
      </div>
    )
  }
}

正如您所见,我试图删除componentWillUnmount中的侦听器,但它说我错过了一个参数?

1 个答案:

答案 0 :(得分:3)

您不应将图片放入state,而是定义如下图像:

constructor(props, context) {
  super(props, context);
  this.img1 = new window.Image();
  this.img2 = new window.Image();
}

而是添加事件监听器,您可以使用图像的onload事件:

onImageLoaded(imgType) {
  if (imgType === 'pre') {
    ...  
  }
  ...
}

this.img1.onload = this.onImageLoaded.bind(this, 'pre');
this.img2.onload = this.onImageLoaded.bind(this, 'real');
...

然后通过为它指定null来删除onload侦听器:

this.img1.onload = null;

如果您使用某些计时器,请始终删除componentWillUnmount()中的计时器,如:

// Create timer..
this.timer1 = setTimeout(() => {...}, 100);

componentWillUnmount() {
  // Remove 
  clearTimeout(this.timer1);
}