为何React组件中useEffect添加又移除监听仍能更新窗口尺寸?
问题解释
这段代码里的useEffect没有传入第二个依赖参数,这意味着它会在组件每一次渲染完成后都执行——包括初始渲染,以及每次状态更新后的重新渲染,并不是只执行一次。
具体执行流程如下:
- 组件首次渲染:执行
useEffect,给window添加resize事件监听,同时返回一个清理函数(这个清理函数不会立刻执行,要等到组件卸载或者下一次useEffect执行前才会触发)。 - 调整浏览器窗口时,
resize事件触发onResize函数,调用setWindowWidth和setWindowHeight更新状态,状态变化会触发组件重新渲染。 - 组件重新渲染时,会先执行上一次
useEffect返回的清理函数(移除之前绑定的onResize监听),然后再执行新的useEffect,给window绑定新的onResize监听(每次渲染生成的onResize是新的函数实例,但不影响事件触发)。 - 所以每次窗口调整触发事件后,都会更新状态、触发重渲染、重新绑定监听,以此循环,组件就能持续显示最新的窗口尺寸。
不过这种写法存在性能问题:每次组件渲染都要解绑再绑定事件监听,而且每次onResize都是新的函数实例。建议优化写法,给useEffect加上空依赖数组[],让它只在组件挂载时绑定一次监听,同时用useCallback包裹onResize避免不必要的函数创建,优化后的代码示例:
import React, { useState, useEffect, useCallback } from 'react'; const WindowSize = () => { const [windowWidth, setWindowWidth] = useState(window.innerWidth); const [windowHeight, setWindowHeight] = useState(window.innerHeight); const onResize = useCallback(() => { console.log("resize detected"); setWindowWidth(window.innerWidth); setWindowHeight(window.innerHeight); }, []); useEffect(() => { window.addEventListener('resize', onResize); return () => { window.removeEventListener('resize', onResize); } }, [onResize]) return ( <div> <p>Width: {windowWidth}</p> <p>Height: {windowHeight}</p> </div> ); }; export default WindowSize;
内容的提问来源于stack exchange,提问作者user9042204
相关产品推荐
相关产品推荐

