I'm developing a React application and encountering an issue with scrolling behavior. Despite setting up conditional scrolling logic based on the component's state, I'm observing an unwanted small vertical scroll before the horizontal scrolling starts. This occurs when transitioning between vertical and horizontal scrolling modes. I really don't understand what it's causing it.
What I want:
What is happening:
My App.tsx where the state is handled.
import "./App.css";
import CurrentLocation from "./components/CurrentLocation";
import Footer from "./components/Footer.js";
import Landing from "./components/Landing";
import { debounce } from "./utils/debounce.js";
function App() {
const [indexScroll, setIndexScroll] = useState(0);
const [indexHoriz, setIndexHoriz] = useState(0);
useEffect(() => {
console.log("Current vertical index: ", indexScroll);
// handle vertical scroll
const handleScrolling = debounce((e: any) => {
// get main element
const main = document.querySelector("main");
e.preventDefault();
// if scrolling up
if (e.wheelDelta <= 0) {
// if we are not at the last div, scroll to next one
if (indexScroll < main?.children.length!! - 1) {
console.log("Scrolling up");
setIndexScroll(indexScroll + 1);
main?.children[indexScroll + 1].scrollIntoView({
behavior: "smooth",
});
} else {
// if last div, go back to the first one
setIndexScroll(0);
main?.children[0].scrollIntoView({
behavior: "smooth",
});
}
} else {
// if scrolling down
// if we are not in the first div, scroll back
if (indexScroll > 0) {
setIndexScroll(indexScroll - 1);
main?.children[indexScroll - 1].scrollIntoView({
behavior: "smooth",
});
} else {
// if we are at the first div, do nothing
console.log("You are at the first div, can't scroll back.");
}
}
}, 50);
// handle horiz scroll
const handleScrollingHoriz = debounce((e: any) => {
// get main element
const main = document.querySelector("#current-location");
e.preventDefault();
// if scrolling up
if (e.wheelDelta <= 0) {
// if we are not at the last div, scroll to next one
if (indexHoriz < main?.children.length!! - 1) {
console.log("Scrolling up");
setIndexHoriz(indexHoriz + 1);
main?.children[indexHoriz + 1].scrollIntoView({
behavior: "smooth",
});
} else {
// if last div, go back to the first one
setIndexHoriz(0);
main?.children[0].scrollIntoView({
behavior: "smooth",
});
}
} else {
// if scrolling down
// if we are not in the first div, scroll back
if (indexHoriz > 0) {
setIndexHoriz(indexHoriz - 1);
main?.children[indexHoriz - 1].scrollIntoView({
behavior: "smooth",
});
} else {
// if we are at the first div, do nothing
console.log("You are at the first div, can't scroll back.");
}
}
}, 50);
// if user is in div n°1 (current location) activate horizontal scrolling
if (indexScroll === 1) {
window.removeEventListener("mousewheel", handleScrolling);
window.addEventListener("mousewheel", handleScrollingHoriz);
} else {
window.addEventListener("mousewheel", handleScrolling);
}
}, [indexScroll, indexHoriz]);
return (
<main>
<Landing />
<CurrentLocation />
<Footer />
</main>
);
}
export default App;
My CurrentLocation component where the divs resides.
import useGeo from "../hooks/useGeo";
const CurrentLocation = () => {
const { geoData, weatherData, geoLoading, weatherLoading } = useGeo();
if (geoLoading || weatherLoading)
return (
<div id="current-location" className="grid">
<p>Loading data</p>
</div>
);
return (
<div id="current-location" className="grid">
<div className="grid-child">
<h1>
It looks like you're in {geoData.city}, {geoData.state_prov}.
<br /> The current weather is{" "}
{weatherData.list[0].weather[0].description} with a temperature of{" "}
{weatherData.list[0].main.temp.toFixed(0)}°F.
</h1>
</div>
<div className="grid-child">FORECAST 5 DAYS</div>
<div className="grid-child">SEARCH LOCATION</div>
</div>
);
};
export default CurrentLocation;
My App.css and index.css
.full-page > div {
display: flex;
justify-content: center;
align-items: center;
height: 90%;
width: 90%;
}
.full-page {
display: flex;
justify-content: center;
align-items: center;
height: 100dvh;
}
#current-location,
.grid-child {
overflow-x: hidden;
}
.grid {
display: grid;
height: 100dvh;
align-items: center;
grid-template-columns: 100vw 100vw 100vw;
}
.grid-child {
display: flex;
justify-content: center;
width: 100vw;
}
body {
box-sizing: border-box;
background-color: black;
color: white;
overflow: hidden;
font-family: "DM Sans", sans-serif;
}
h1 {
padding: 30px;
font-size: 2.5em;
font-weight: 400;
}
Found a solution. The .grid-child was resizing on scrolling based on the height of the following div and making it looking like a scroll problem. I added a fixed height of full screen to the class.
.grid-child {
display: flex;
justify-content: center;
align-items: center;
width: 100vw;
height: 100dvh;
}