Description
I’m encountering an issue with the header component in my React based next.js web application. Upon the initial load of the page, when I first scroll, there’s a noticeable jittery behavior before the header hides as intended. Once this initial jittery behavior occurs, the header behaves perfectly fine for subsequent scrolls.
function Header() {
const [mounted, setMounted] = useState(false);
const { theme } = useTheme();
const [prevScrollPos, setPrevScrollPos] = useState(0);
const [visible, setVisible] = useState(true);
useEffect(() => {
const handleScroll = () => {
const currentScrollPos = window.scrollY;
setVisible(prevScrollPos > currentScrollPos || currentScrollPos < 200);
setPrevScrollPos(currentScrollPos);
};
window.addEventListener("scroll", handleScroll);
return () => window.removeEventListener("scroll", handleScroll);
}, [prevScrollPos]);
useEffect(() => {
setMounted(true);
}, []);
if (!mounted) {
return null;
}
return (
<>
{(theme === 'light' || theme === 'undefined' || theme === null) && visible && <LightHeader />}
{theme === 'dark' && visible && <DarkHeader />}
</>
)
}
(I am using next-themes for theme switching. The mounting logic is to mitigate hydration error)
I suspect I might be missing a crucial React concept or best practice here. Could someone please provide insights into what might be causing this jittery behavior on the first scroll and how I can resolve it? Would de-bouncing help in this scenario? Additionally, could this issue be related to React Snapshot?
Any help or guidance would be greatly appreciated! Thank you.
2
Answers
The issue was with scroll not able to anchor due to dynamically adding and removing the header component. I was rendering either the header component or null which was affecting the height of the document.
I mitigated this issue by using visibility: visible and hidden such that it is still in the document flow but hidden.
NOTE: I still don't know why the issue resolves itself after initial jitter tho. Is it because the height of the header is saved by the document?
I haven’t reproduced the problem yet. But these two things might help.
First, add visible to the useEffect’s dependency list(I’m sure there’s a warning by the linter):
Second, change
useState
touseRef
for the mounted variable:Using
useRef
avoids unnecessary renders.