如何配置useEffect依赖,在屏幕尺寸变化时更新滑块拖拽边界
原有写法失效的核心原因
useEffect的依赖触发逻辑非常简单:仅当依赖项的值在两次组件渲染的间隙发生变化,才会触发effect重新执行。
你之前尝试的依赖写法完全不满足这个逻辑:
- 把
document.getElementById('slider')、document.getElementById('root')作为依赖:DOM节点的引用在组件初次挂载完成后就不会发生变化,且DOM层面的操作永远不会触发组件重渲染,依赖对比会一直判定值没有变化,自然不会重跑effect。 - 把
window.innerWidth作为依赖:窗口尺寸变化是浏览器层面的全局事件,不会主动驱动React组件重渲染,组件渲染周期内这个值根本不会有任何变化,依赖检测永远发现不了差异。
另外原有代码还有两个会影响运行的隐患:
- 没有对DOM挂载状态做兜底,初次执行effect时如果ref对应的DOM还没渲染完成,会直接因为读取null的属性报错
- 每次执行effect都直接创建新的Draggable实例,没有销毁旧实例,多次执行后会积累大量残留拖拽实例,导致拖拽响应混乱、页面卡顿。
可直接运行的修正实现
- 新增resize事件监听,把窗口尺寸同步为组件内的响应式state,尺寸变化时主动触发组件重渲染,从根源上让React能追踪到尺寸变化
- 直接通过已绑定的
sliderRef读取滑块宽度,替代硬编码的全局DOM查询,提升代码稳定性 - 为Draggable实例增加销毁逻辑,在effect重跑或组件卸载时清理旧实例,避免逻辑冲突
import { useEffect, useRef, useState } from 'react'; import Draggable from 'gsap/Draggable'; function DraggableSlider() { const sliderRef = useRef(null); // 初始化窗口宽度状态,初始值取当前窗口的实际宽度 const [currentWindowWidth, setCurrentWindowWidth] = useState(window.innerWidth); // 监听窗口尺寸变化,同步更新state驱动重渲染 useEffect(() => { const syncWindowSize = () => { setCurrentWindowWidth(window.innerWidth); }; window.addEventListener('resize', syncWindowSize); // 组件卸载时移除事件监听,避免内存泄漏 return () => window.removeEventListener('resize', syncWindowSize); }, []); // 拖拽实例创建逻辑,依赖窗口宽度状态自动适配边界 useEffect(() => { // DOM未挂载时直接跳过执行,避免报错 if (!sliderRef.current) return; const sliderTotalWidth = sliderRef.current.offsetWidth; // 计算适配当前窗口尺寸的最大拖拽位移 const maxDragX = currentWindowWidth - sliderTotalWidth; // 创建拖拽实例,存为局部变量方便后续销毁 const dragInstance = Draggable.create(sliderRef.current, { type: "x", bounds: { minX: 0, maxX: -maxDragX } })[0]; // Draggable.create返回实例数组,取第一个绑定的目标元素实例 // 清理函数:effect重跑或组件卸载时销毁旧拖拽实例 return () => { dragInstance?.kill(); } // 窗口宽度变化时,自动重跑逻辑更新拖拽边界 }, [currentWindowWidth]); return ( <div ref={sliderRef} id="slider" className="draggable-slider"> {/* 滑块内容区域 */} </div> ) }
补充注意事项
- 不要把DOM节点、全局浏览器属性直接作为useEffect的依赖项,这类值的变化不会纳入React的渲染追踪流程,永远无法通过依赖对比触发effect执行
- 所有需要响应式驱动渲染的全局值,都要通过事件监听同步为组件内的state,再作为依赖项传入
- 引入需要手动销毁的第三方实例类库时,一定要在effect的清理函数中调用实例的销毁方法,避免多次执行effect生成的残留实例造成逻辑异常
内容的提问来源于stack exchange,提问作者Ruan Duarte
相关产品推荐
相关产品推荐

