首页 > 解决方案 > 使用自定义布局组件反应 useEffect 奇怪的行为

问题描述

我正在尝试在我的网络投资组合中为我的动画使用滚动位置。由于这个投资组合使用 nextJS,我不能依赖窗口对象,而且我使用的是导航宽滑块,所以我实际上不是在窗口中滚动,而是在一个名为 Page 的布局组件中滚动。

import React, { useEffect } from 'react';
import './page.css';

const Page = ({ children }) => {

  useEffect(() => {
    const scrollX = document.getElementsByClassName('page')
    const scrollElement = scrollX[0];
    console.log(scrollX.length)
    console.log(scrollX)
    scrollElement.addEventListener("scroll", function () {
      console.log(scrollX[0].scrollTop)
    });
 
    return () => {
      scrollElement.removeEventListener("scroll", () => { console.log('listener removed') })
    }
  }, [])


  return <div className="page">{children}</div>;
};

export default Page;

这是一个生产版本:https ://next-portfolio-kwn0390ih.vercel.app/

加载时,DOM 中只有一个 Page 组件。

行为如下:

问题是:当您从第一个导航到第二个时,一切看起来都很好,但是如果您返回第一页,您会注意到控制台正在记录第二个侦听器而不是第一个侦听器的 scrollX 值。每次您进入第二页时,即使它不是同一个 Page 组件,它似乎也会向同一个 scrollElement 添加另一个侦听器。

我怎样才能做到这一点 ?我猜这两个组件正在尝试访问相同的 scrollElement :/

谢谢你的时间。

标签: reactjsreact-hooksnext.jsuse-effect

解决方案


很酷的网站。我们没有完整的信息,但我怀疑尝试使用document.getElementsByClassName('page')[0]. 当您转到第 2 页时,日志scrollX会给出一个包含 2 个元素的 HTMLCollection。所以有一个问题是针对哪个。我会考虑使用 refs 代替。像这样:

import React, { useEffect, useRef } from 'react';
import './page.css';

const Page = ({ children }) => {

  const pageRef = useRef(null)

  const scrollListener = () => {
    console.log(pageRef.current.scrollTop)
  }

  useEffect(() => {
    pageRef.addEventListener("scroll", scrollListener );
 
    return () => {
      pageRef.removeEventListener("scroll", scrollListener )
    }
  }, [])


  return <div ref={pageRef}>{children}</div>;
};

export default Page;

这更清晰,我认为将减少组件之间关于每个滚动侦听器引用的 dom 元素的混淆。就第三页而言,您scrollX仍在记录相同的 HTMLElement 集合,其中包含 2 个元素。根据您的模式,应该有 3 个。(虽然实际上应该只有 1 个!)所以第 3 页上的某些内容没有正确呈现。如果我们看到更多代码,它可能会发现错误是其他错误。如果 refs 没有解决它,你能发布Page在更大范围内是如何实现的吗?

另外,从“初级开发人员”标题中删除“初级” - 你不会后悔的


推荐阅读