You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;

关键说明:

  1. useCallback的作用:把bottomScrollDetection函数缓存起来,只有当依赖dispatch变化时才重新生成,这样添加和移除监听器用的是同一个函数引用,确保移除生效。
  2. useEffect清理函数:React会在组件卸载或者useEffect的依赖变化时自动执行这个返回的函数,不管是all_loaded变为true还是组件卸载,都能保证监听器被正确清理。
  3. 滚动触发条件优化:将position === limit改为position >= limit - 10,避免因为滚动精度问题,导致刚好触底却无法触发加载的情况。

内容的提问来源于stack exchange,提问作者some nooby questions

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 09:23:08