const shouldHide = useHideOnScroll();
return shouldHide ? null : <div>something</div>
usehideonscroll行为应不在每个滚动上返回更新的值,而仅在发生更改时。
伪逻辑是以下内容:
if (scrolledDown && !isHidden) {
setIsHidden(true);
} else if (scrolledUp && isHidden) {
setIsHidden(false);
}
用文字,如果向下滚动而不是隐藏,则隐藏。如果向上滚动并隐藏了,则请不通过。但是,如果向下滚动并隐藏隐藏,什么都不做或滚动而不是隐藏,什么也不做。
您如何用钩子实现它?
在这里:
const useHideOnScroll = () => {
const prevScrollY = React.useRef<number>();
const [isHidden, setIsHidden] = React.useState(false);
React.useEffect(() => {
const onScroll = () => {
setIsHidden(isHidden => {
const scrolledDown = window.scrollY > prevScrollY.current!;
if (scrolledDown && !isHidden) {
return true;
} else if (!scrolledDown && isHidden) {
return false;
} else {
prevScrollY.current = window.scrollY;
return isHidden;
}
});
};
console.log("adding listener");
window.addEventListener("scroll", onScroll);
return () => {
window.removeEventListener("scroll", onScroll);
};
}, []);
return isHidden;
};
const Navbar = () => {
const isHidden = useHideOnScroll();
console.info("rerender");
return isHidden ? null : <div className="navbar">navbar</div>;
};
export default Navbar;
您可能会担心setIsHidden
在每个onScroll
上引起rerender,始终返回一些新的状态值,但是useState
中的设置器足够聪明,只有在值实际更改时才更新。
您的 .navbar
(我添加了一个类)在出现时不应更改布局,否则您的片段将被锁定在无限循环中。这里也适合它:
.navbar {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 30px;
background: rgba(255, 255, 255, 0.8);
}
完整的代码框:https://codesandbox.io/s/13kr4xqrwq
使用React(16.8.0 )中的钩子
import React, { useState, useEffect } from 'react'
function getWindowDistance() {
const { pageYOffset: vertical, pageXOffset: horizontal } = window
return {
vertical,
horizontal,
}
}
export default function useWindowDistance() {
const [windowDistance, setWindowDistance] = useState(getWindowDistance())
useEffect(() => {
function handleScroll() {
setWindowDistance(getWindowDistance())
}
window.addEventListener('scroll', handleScroll)
return () => window.removeEventListener('scroll', handleScroll)
}, [])
return windowDistance
}
您需要使用window.addeventlistener和https://reactjs.org/docs/hooks-custom.html指南。
那是我的工作示例:
import React, { useState, useEffect } from "react";
const useHideOnScrolled = () => {
const [hidden, setHidden] = useState(false);
const handleScroll = () => {
const top = window.pageYOffset || document.documentElement.scrollTop;
setHidden(top !== 0);
};
useEffect(() => {
window.addEventListener("scroll", handleScroll);
return () => {
window.removeEventListener("scroll", handleScroll);
};
}, []);
return hidden;
};
export default useHideOnScrolled;
实时演示:https://codesandbox.io/s/w0p3xkoq2l?fontsize=14
我认为名称 useIsScrolled()
或类似的东西会更好
悬挂数小时后,这是我想到的。
const useHideOnScroll = () => {
const [isHidden, setIsHidden] = useState(false);
const prevScrollY = useRef<number>();
useEffect(() => {
const onScroll = () => {
const scrolledDown = window.scrollY > prevScrollY.current!;
const scrolledUp = !scrolledDown;
if (scrolledDown && !isHidden) {
setIsHidden(true);
} else if (scrolledUp && isHidden) {
setIsHidden(false);
}
prevScrollY.current = window.scrollY;
};
window.addEventListener("scroll", onScroll);
return () => {
window.removeEventListener("scroll", onScroll);
};
}, [isHidden]);
return isHidden;
};
用法:
const shouldHide = useHideOnScroll();
return shouldHide ? null : <div>something</div>
它仍然是次优的,因为当isHidden
更改时,我们重新分配了onScroll
。其他一切都感觉太粗糙和无证件。我真的有兴趣找到一种做同样的方法,而无需重新分配onScroll
。如果您知道一种方法:)