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

useEffect仅在热重载时运行,子组件滑动事件绑定失效如何解决?

问题根因

  • 子组件顶层直接取const card = cardRef.current,组件首次渲染时DOM还未挂载,cardRef.current为null,后续即使DOM挂载完成,这个顶层变量也不会自动更新。只有热重载时组件二次渲染、DOM已存在的情况下才会拿到正确的DOM节点,所以事件绑定仅偶尔生效。
  • 事件绑定useEffect没有指定依赖数组,且没有做事件解绑逻辑,不仅会导致重复绑定,还会引发内存泄漏。
  • 子组件中setSwiped是异步更新,直接在setSwiped后调用props.parentCallback(swiped),传递的是更新前的旧值,会导致父组件计数异常。

修复方案

子组件修改后代码

function Profile(props: any) {
  const [name] = useState(`${props.profile.name.title} ${props.profile.name.first} ${props.profile.name.last}`);
  const [swiped, setSwiped] = useState(0)
  const backgroundImage = {
    backgroundImage: `url(${props.profile.picture.large})`
  };
  const cardRef = useRef<HTMLDivElement>(null);

  let startX:any = null;

  function unify (e:any) { return e.changedTouches ? e.changedTouches[0] : e };

  function lock (e:any) { 
    // 直接从ref取最新的DOM节点,不要用顶层变量
    if (cardRef.current) {
      startX = unify(e).clientX; 
      console.log(startX)
    } 
  }

  function move (e: any) {
    console.log('move')
    if(startX) {
      let differenceX = unify(e).clientX - startX, sign = Math.sign(differenceX);
      if(sign < 0 || sign > 0) {
        setSwiped((prev) => {
          const newSwiped = prev +1
          // 拿到更新后的值再传给父组件
          props.parentCallback(newSwiped);
          return newSwiped
        })
        startX = null
      }
    }
  }

  // 依赖数组留空,仅在组件挂载完成后执行一次绑定,卸载时解绑
  useEffect(() => {
    const card = cardRef.current;
    if (card) {
      console.log(card)
      card.addEventListener('mousedown', lock, false);
      card.addEventListener('touchstart', lock, false);
      
      card.addEventListener('mouseup', move, false);
      card.addEventListener('touchend', move, false);
    }
    // 返回清理函数,组件卸载时解绑事件
    return () => {
      if (card) {
        card.removeEventListener('mousedown', lock, false);
        card.removeEventListener('touchstart', lock, false);
        card.removeEventListener('mouseup', move, false);
        card.removeEventListener('touchend', move, false);
      }
    }
  }, [])
  return (
    <div>
      <h1 className="heading-1">{name}</h1>
      <div ref={cardRef} className="card" style={backgroundImage}>
      </div>
    </div>
  );
}

父组件说明

父组件现有逻辑可正常运行,无需额外修改。

内容的提问来源于stack exchange,提问作者codeDragon

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 18:57:01