const shouldHide = useHideOnScroll();
return shouldHide ? null : <div>something</div>
The useHideOnScroll behaviour should return updated value not on every scroll but only when there is a change.
The pseudo logic being something like the following:
if (scrolledDown && !isHidden) {
setIsHidden(true);
} else if (scrolledUp && isHidden) {
setIsHidden(false);
}
In words, if scroll down and not hidden, then hide. If scroll up and hidden, then unhide. But if scroll down and hidden, do nothing or scroll up and not hidden, do nothing.
How do you implement that with hooks?
Here:
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;
You might have concern about setIsHidden causing rerender on every onScroll, by always returning some new state value, but a setter from useState is smart enough to update only if the value has actually changed.
Also your .navbar (I've added a class to it) shouldn't change the layout when it appears or your snippet will get locked in an infinite loop. Here're appropriate styles for it as well:
.navbar {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 30px;
background: rgba(255, 255, 255, 0.8);
}
Full CodeSandbox: https://codesandbox.io/s/13kr4xqrwq
Using hooks in 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
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With