前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >react移除监听事件无效

react移除监听事件无效

作者头像
OECOM
发布2020-07-02 11:56:09
3.4K0
发布2020-07-02 11:56:09
举报
文章被收录于专栏:OECOMOECOMOECOM

问题描述

首先先来复现一下代码,背景是这样的,需要监听一下scroll事件,但是监听函数需要当前组件的this环境,所以监听函数上需要bind(this), 但是这样操作后发现无法removeEventListener这个监听,提示: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.

handleScroll(){
    this.setStaete()  //举例不一定用到setState
    }
 componentWillMount(){
        window.addEventListener('scroll', this.handleScroll.bind(this));
    }

    /** 组件销毁后必要的清理*/
    componentWillUnmount(){
        window.removeEventListener('scroll', this.handleScroll.bind(this))
    }

当我这样写了以后发现销毁组件的时候无法销毁。其实原因就在于添加了bind(this),如果没有他就会很方便的移除,一旦加上了bind(this),就失败了。

addEventListener、removeEventListener与事件处理程序

首先先来了解一下这两个函数的使用。addEventListener()和removeEventListener()是“DOM2级事件”中定义的两个方法,分别用于添加和删除事件处理程序。所有的DOM节点中都包含这两个方法,并且它们都接受3个参数:要处理的事件名、要为事件添加的处理程序的函数和一个表示事件处理阶段的布尔值。

这里重点是添加处理的函数,addEventListener()和removeEventListener()添加的处理函数必须是同一个函数,什么叫同一个函数呢,就是说这两个函数时相等的,指向同一个地址。我们都知道匿名函数是无法移除的,原因就在于此,直接添加的匿名函数时无法实现另一个匿名函数和此匿名函数相等。

window.addEventListener('scroll', function(e){
    console.log(e)
});
window.removeEventListener('scroll', function(e){
    console.log(e)
});

如上代码所示,虽然两个匿名函数写的一样,但是在程序上来说,这两个匿名函数是不相同的,所以匿名函数无法移除,这就是根源所在。

那么我们再来看一下为何加了bind(this)之后也无法移除呢。那先来看看bind的作用。

const test = {
    name:'oecom',
    getName:function(){
        console.log(this.name)
    }
}
test.getName()//输出oecom

然后我们对代码进行稍加改动

const test = {
    name:'oecom',
    getName:function(){
        console.log(this.name)
    }
}
const func = test.getName;
func();//这里直接输出了undefined
const func1 = test.getName.bind(test);
func1();//这里直接输出oecom

很明显,bind是为了指明this的指向,解决this丢失的问题。那么为何会加上bind之后无法移除呢,我们来看一下下面的两个代码

let func1 = test.getName.bind(test);
let func2 = test.getName.bind(test);
let func3 = test.getName;
let func4 = test.getName;
console.log(func1==func2)
console.log(func3==func4)
react移除监听事件无效
react移除监听事件无效

我想看到了上图的输出结果,大家应该明白了为何加上bind之后会无法移除监听事件了,其根源就在于每次加上bind之后返回的函数并不是指向同一个函数

解决方案

既然明白了原因所在,那么我们来说一下如何解决。具体思路有两个,其中一个是在constructor中提前声明好:

constructor(){
    super();
    this.scrollEvent = this.handleScroll.bind(this)
}
handleScroll(){
    this.setStaete()  //举例不一定用到setState
    }
 componentWillMount(){
        window.addEventListener('scroll', this.scrollEvent);
    }

    /** 组件销毁后必要的清理*/
    componentWillUnmount(){
        window.removeEventListener('scroll', this.scrollEvent)
    }

另一种方式则是使用箭头函数了:

handleScroll = ()=>{
    this.setStaete()  //举例不一定用到setState
    }
 componentWillMount(){
        window.addEventListener('scroll', this.handleScroll);
    }
    /** 组件销毁后必要的清理*/
    componentWillUnmount(){
        window.removeEventListener('scroll', this.handleScroll)
    }
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-04-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 问题描述
  • addEventListener、removeEventListener与事件处理程序
  • 解决方案
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档