React中useEffect内removeEventListener失效问题求助
解决React+Redux懒加载scroll监听器无法移除的问题
问题出在你定义的bottomScrollDetection函数每次组件渲染都会重新创建,导致移除事件时用的函数引用和添加时的不是同一个,自然没法移除。另外你的useEffect写法也不符合React最佳实践,应该用清理函数来处理事件监听器的移除。
修改步骤:
- 用
useCallback缓存bottomScrollDetection函数,保证其引用稳定 - 调整useEffect逻辑,利用清理函数统一处理监听器移除
修改后的代码:
import { useCallback, useEffect } from 'react'; import { useAppSelector, useAppDispatch } from './app/hooks'; import { fetchProducts } from './features/products/productsSlice'; const ProductList = () => { const { all_loaded } = useAppSelector((state) => state.productsSlice); const dispatch = useAppDispatch(); // 用useCallback缓存函数,确保引用稳定 const bottomScrollDetection = useCallback(() => { const position = window.scrollY; const limit = document.body.offsetHeight - window.innerHeight; // 优化触发条件,避免滚动精度问题导致无法触发 if (position >= limit - 10) { dispatch(fetchProducts(true)); } }, [dispatch]); useEffect(() => { // 首次加载数据 if (!all_loaded) { dispatch(fetchProducts(false)); document.addEventListener("scroll", bottomScrollDetection); } // 清理函数:组件卸载或依赖变化时自动移除监听器 return () => { document.removeEventListener("scroll", bottomScrollDetection); }; }, [all_loaded, bottomScrollDetection]); // 商品列表渲染逻辑 return <div>{/* 你的商品列表内容 */}</div>; }; export default ProductList;
关键说明:
- useCallback的作用:把
bottomScrollDetection函数缓存起来,只有当依赖dispatch变化时才重新生成,这样添加和移除监听器用的是同一个函数引用,确保移除生效。 - useEffect清理函数:React会在组件卸载或者useEffect的依赖变化时自动执行这个返回的函数,不管是
all_loaded变为true还是组件卸载,都能保证监听器被正确清理。 - 滚动触发条件优化:将
position === limit改为position >= limit - 10,避免因为滚动精度问题,导致刚好触底却无法触发加载的情况。
内容的提问来源于stack exchange,提问作者some nooby questions
相关产品推荐
相关产品推荐

