i have a bug where a useEffect hook is stopping a scrollIntoView call from completing only on chromium browsers. i imagine there's something i'm not understanding about useEffect. any help's appreciated 🙂



below are the source files aswell as per stack overflow guidelines. tried to make it a so snippet but it didn't wanna work.
import { useEffect, useRef, useState } from 'react';
import './styles.css';
export default function App() {
const generateSections = amount => {
return [...Array(amount).keys()]
.map(number => number + 1)
.map(number => {
return {
text: `section:${number}`,
id: `#section-${number}`,
};
});
};
const sections = generateSections(10);
const sectionRefs = useRef([]);
const sectionLinkRefs = useRef([]);
const navRef = useRef();
const [activeSectionId, setActiveSectionId] = useState(sections[0].id);
// 📌 update the active section on scroll (active section is used for styling and other logic)
useEffect(() => {
const changeActiveSection = () => {
// a small buffer is a bit more intuitive
const buffer = 50;
const amountScrolled = window.scrollY + navRef.current.clientHeight + buffer;
// check what section is scrolled to on the page
const haveScrolledIntoSection = section => {
const sectionTop = sectionRefs.current[section.id].offsetTop;
const sectionBottom = sectionRefs.current[section.id].clientHeight + sectionTop;
return amountScrolled >= sectionTop && amountScrolled <= sectionBottom;
};
// set the active section to be the section scrolled to on the page
setActiveSectionId(activeSectionId => sections.find(haveScrolledIntoSection)?.id ?? activeSectionId);
};
window.addEventListener('scroll', changeActiveSection);
return () => window.removeEventListener('scroll', changeActiveSection);
});
// 📌 center the active section nav link if the active section changes
useEffect(() => {
const activeSectionLink = sectionLinkRefs.current[activeSectionId];
const remainingNavWidth = navRef.current.clientWidth - activeSectionLink.clientWidth;
navRef.current.scrollLeft = activeSectionLink.offsetLeft - remainingNavWidth / 2;
}, [activeSectionId]);
const scrollToSection = sectionId => {
// 📌📌📌 here is where the bug is! 📌📌📌
const scrollBehavior = 'smooth';
// const scrollBehavior = 'auto';
sectionRefs.current[sectionId].scrollIntoView({ behavior: scrollBehavior });
};
return (
<div>
<nav ref={navRef}>
{sections.map(section => {
const addSectionLinkRef = (ref, sectionId) => {
if (sectionLinkRefs.current[sectionId] === undefined) sectionLinkRefs.current[sectionId] = ref;
};
return (
<h1
ref={ref => addSectionLinkRef(ref, section.id)}
onClick={() => scrollToSection(section.id)}
className={section.id === activeSectionId ? 'active' : ''}
key={section.id}
>
{section.text}
</h1>
);
})}
</nav>
<main>
{sections.map(section => {
const addSectionRef = (ref, sectionId) => {
if (sectionRefs.current[sectionId] === undefined) sectionRefs.current[sectionId] = ref;
};
return (
<section
ref={ref => addSectionRef(ref, section.id)}
className={section.id === activeSectionId ? 'active' : ''}
key={section.id}
>
{section.text}
</section>
);
})}
</main>
</div>
);
}
import { StrictMode } from "react";
import ReactDOM from "react-dom";
import App from "./App";
const rootElement = document.getElementById("root");
ReactDOM.render(
<StrictMode>
<App />
</StrictMode>,
rootElement
);
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
:root {
--nav__height: 12.5vh;
--section__height: calc(100vh - var(--nav__height) - (var(--padding) * 2));
--padding: 10px;
--color-primary--normal: #004d40;
--color-primary--dark: #00251a;
--color-primary--light: #39796b;
--color-secondary--normal: #37474f;
--color-secondary--dark: #102027;
--color-secondary--light: #62727b;
}
nav {
height: var(--nav__height);
width: 100vw;
background-color: var(--color-primary--normal);
padding: var(--padding);
overflow-x: scroll;
scrollbar-width: none;
-ms-overflow-style: none;
display: flex;
position: fixed;
gap: var(--padding);
}
nav::-webkit-scrollbar {
display: none;
}
h1 {
display: grid;
height: 100%;
width: max-content;
background-color: var(--color-primary--dark);
place-content: center;
padding: var(--padding);
color: var(--color-secondary--normal);
}
.active {
text-decoration: underline;
color: white;
}
main {
padding: var(--padding);
padding-top: calc(var(--nav__height) + var(--padding));
background-color: var(--color-secondary--normal);
display: flex;
gap: var(--padding);
flex-direction: column;
}
section {
height: var(--section__height);
display: grid;
place-content: center;
background-color: var(--color-secondary--light);
font-size: 2rem;
}
Wrapping the scrollIntoView call with setTimeout worked for me.
Example:
setTimeout(() => {
element.scrollIntoView({
behavior: "smooth",
block: "center",
inline: "center"
});
}, 0);
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