关于React中ComponentWillUnmount与滚动事件解绑的疑问求助
嘿,我来帮你把这两个困惑彻底理清楚,咱们结合你的代码和React的工作原理一步步说:
一、为什么必须调用componentWillUnmount与removeEventListener才能让功能正常?
先看你的代码:在componentDidMount里给window添加了滚动事件监听this.handleScroll。这里要注意一个关键点:window是全局对象,它的生命周期和你的React组件完全无关。
当你的ScrollPos组件被销毁(比如路由切换、条件渲染让它消失)时,组件本身的实例会被标记为可回收,但你之前给window绑定的监听事件并不会自动消失!如果不手动移除:
- 每次页面滚动,依然会触发
this.handleScroll方法,但此时组件已经不存在了,要是handleScroll里有this.setState这类操作,直接就会抛出错误(因为组件实例已经被销毁,无法更新状态)。 - 更隐蔽的是内存泄漏:事件监听器会一直持有组件实例的引用,导致垃圾回收机制无法回收这个实例,时间长了会拖慢页面性能。
所以必须在组件销毁前,通过componentWillUnmount钩子调用removeEventListener,把绑定在全局对象上的监听清理掉,避免这些问题。
二、componentWillUnmount的作用是什么?为什么没它滚动事件就不正常?
componentWillUnmount是React类组件生命周期里组件销毁前执行的最后一个钩子,它的核心职责就是做清理工作——把组件运行过程中产生的、不会自动消失的副作用全部清除,比如:
- 移除全局/第三方对象上的事件监听
- 取消定时器(
setTimeout/setInterval) - 取消网络请求(比如Axios的cancelToken)
- 清理订阅的外部数据源
回到你的滚动事件场景:如果没有componentWillUnmount里的清理操作,就会出现我刚才说的问题——组件没了,但监听还在,滚动时触发的方法找不到对应的组件实例,要么报错,要么做无意义的操作,自然就“功能不正常”了。
举个完整的代码示例,补全你的componentWillUnmount部分:
import React, { Component } from 'react'; class ScrollPos extends Component { state = { position: null } handleScroll = () => { this.setState({ position: window.scrollY }); } componentDidMount() { console.log('componentDidMount Fired') window.addEventListener('scroll', this.handleScroll) } componentWillUnmount() { console.log('componentWillUnmount Fired') // 必须和添加监听时用同一个方法引用,才能正确移除 window.removeEventListener('scroll', this.handleScroll) } }
这里还要注意:移除监听时必须用和添加时完全相同的方法引用,所以建议把handleScroll定义为类的箭头函数(或者在构造函数里bind),避免每次渲染创建新的函数引用,导致无法正确移除监听。
内容的提问来源于stack exchange,提问作者John Bryant

