我正在尝试检测Scroll事件是向上还是向下,但我找不到解决方案。
import React, { useState, useEffect } from "react";
import { Link } from "react-router-dom";
const Navbar = ({ className }) => {
const [y, setY] = useState(0);
const handleNavigation = (e) => {
const window = e.currentTarget;
if (y > window.scrollY) {
console.log("scrolling up");
} else if (y < window.scrollY) {
console.log("scrolling down");
}
setY(window.scrollY);
};
useEffect(() => {
setY(window.scrollY);
window.addEventListener("scroll", (e) => handleNavigation(e));
}, []);
return (
<nav className={className}>
<p>
<i className="fas fa-pizza-slice"></i>Food finder
</p>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
</ul>
</nav>
);
};
export default Navbar;
基本上,它总是被检测为“关闭”,因为handleNavigation
中的y
始终为0。如果我在DevTool中检查状态,则y
状态会更新,但在handleNavigation
中不会。
有什么建议吗?我做错了什么?
谢谢你的帮忙
9条答案
按热度按时间kkih6yb81#
这是因为您定义了一个没有任何依赖项的**
useEffect()
,所以您的useEffect()
只会运行一次,并且不会在y
更改时调用handleNavigation()
**。要解决这个问题,您需要将y
添加到依赖项数组中,以便在y
值发生更改时通知您的useEffect()
运行。然后,您需要在代码中进行另一项更改才能生效,因为您正在尝试使用window.scrollY
初始化y
,因此您应该在useState()
中执行如下操作:如果由于某种原因窗口可能在那里不可用,或者您不想在这里执行,您可以在两个单独的e1d10d1中执行此操作。
因此,您的e1d11d1应该是这样的:
更新(工作方案)
在我自己实施了这个解决方案之后。我发现有一些注意事项应该适用于这个解决方案。因此由于
handleNavigation()
将直接更改y
值,我们可以忽略y
作为依赖项,然后将handleNavigation()
作为依赖项添加到useEffect()
,然后由于此更改,我们应该优化handleNavigation()
,因此我们应该使用useCallback()
。那么最终的结果将是这样的:在@RezaSam的一条评论之后,我注意到我在备忘版本中犯了一个很小的错误。当我在另一个箭头函数中调用
handleNavigation
时,我发现(通过浏览器开发工具,事件侦听器选项卡)在每个组件重现器中,它将向window
注册一个新事件,因此它可能会毁了整个事情。工作演示:
最终优化方案
毕竟,我的结论是,在这种情况下,memoization将帮助我们注册单个事件,识别滚动方向,但它在打印控制台时并未完全优化,因为我们在
handleNavigation
函数中进行了调整,在当前实现中没有其他方法来打印所需的控制台。所以,我意识到,每当我们想要检查新位置时,有一种更好的方法来存储最后一页滚动位置。此外,为了消除大量的安慰“向上滚动”和“向下滚动*”,我们应该定义一个阈值*(使用去反跳方法)*来触发滚动事件更改。所以我只是在网上搜索了一下,最终得到了这个gist,它非常有用。然后在它的启发下,我实现了一个更简单的版本。
它看起来是这样的:
它是如何工作的?
我将简单地从上到下解释每个代码块。
0
定义了一个临界点,每当滚动向上或向下时,它都会进行新的计算,如果你不想立即计算新的页面偏移量,可以增加它。pageYOffset
,而不是scrollY
。updateScrollDir
函数中,我们将简单地检查是否满足阈值,如果满足,我将根据当前和上一页偏移量指定滚动方向。onScroll
函数。我只是使用requestAnimationFrame
来确保在滚动后页面完全呈现后计算新的偏移量。然后使用ticking
标志,我们将确保在每个requestAnimationFrame
中只运行一次事件侦听器回调。scrollDir
状态将包含实际滚动方向。工作演示:
8i9zcol22#
在Next.js中尝试一下(如果你正在苦苦挣扎)-
我用过这个包-react-use-scroll-direction
mmvthczy3#
我只是想提出一个整洁的解决方案,它很像哈巴汉,但在我看来看起来更整洁一些。
在这里,您只需访问
hidden
状态,即可在代码中随心所欲地执行操作。mo49yndu4#
我发现这个简洁而简单的解决方案只需要几行代码
OnWheels合成事件返回一个事件对象,该对象具有一个名为
nativeEvent
的属性,其中包含原始事件信息。即使没有有效的滚动(overflow:hidden
),也可以使用WEELDELTA检测方向。这是原始源->http://blog.jonathanargentiero.com/detect-scroll-direction-on-react/
bis0qfac5#
在我看来,大多数答案似乎有点过度设计。
以下是我在Nextjs项目中使用的内容:
然后我像这样使用它作为我的组件:
mccptt676#
我环顾四周,找不到一个简单的解决方案,所以我查看了事件本身,发现存在一个“deltaY”,它使一切变得更加简单(不需要保持最后滚动值的状态)。“deltaY”值显示事件在“y”中的变化(正的deltaY表示它是向下滚动的事件,负的deltaY表示它是向上滚动的事件)。
以下是它的工作原理:
brccelvz7#
以下是我的React挂钩解决方案
useScrollDirection
:用途:
基于https://github.com/pwfisher/scroll-intent和https://github.com/dollarshaveclub/scrolldir。也被移植到这里React:https://github.com/AnakinYuen/scroll-direction。
nr9pn0ug8#
以下是我的解决方案,它扩展了这里找到的一些想法。它在每次方向改变时只触发一次,并添加一些参数来微调钩子调用
Codepen demo
cbeh67ev9#
我已经找了这个东西好几个小时了。但是没有一个解决方案对我有效,所以我这样写,并为我的next.js项目工作。