I am developing an app where on mouse wheel up and down navigates the user to different routes in the App. I also have animations corresponding to which way the user scrolls: when scrolling down the next route will intialize from below and the previous route will exit from below, and vice-versa.
this part has been simple enough to implement as per the code below(link to full live working example at the bottom of this post):
Custom Hook UseAppDirection.js
import { useState, useEffect, useContext } from "react";
import { useLocation, useNavigate } from "react-router-dom"
function useAppDirection(navDown, navUp, directionValueDown, directionValueUp) {
const navigate = useNavigate();
const location = useLocation();
const { pathname } = location;
const [isUp, setIsUp] = useState(false);
useEffect(() => {
function handleNavigation(e) {
if (e.deltaY > 1) {
setIsUp(false)
setTimeout(() => {
navigate(navDown, { state: { value: directionValueDown } });
}, 200)
} else if (e.deltaY < 1) {
setIsUp(true)
setTimeout(() => {
navigate(navUp, { state: { value: directionValueUp } });
}, 200)
}
}
window.addEventListener("wheel", handleNavigation);
return () => window.removeEventListener("wheel", handleNavigation);
}, [pathname]);
return { location, isUp }
}
export default useAppDirection
AboutMe.js
import React from "react";
import { motion } from "framer-motion";
import useAppDirection from "../Hooks/useAppDirection";
export default function AboutMe() {
const { isUp, location } = useAppDirection("/work", "/skills", 1000, -1000);
return (
<motion.div
className="aboutme--top"
initial={{ opacity: 0, y: location.state.value, transition: { duration: 0.8 } }}
animate={{ opacity: 1, y: 0, transition: { duration: 0.8 } }}
exit={{ opacity: 0, y: isUp ? 1300 : -1300, transition: { duration: 0.8 } }}
>
</motion.div >
)
}
However one major problem I have ran into is when a user scrolls one direction and in mid transition scrolls the opposite direction; both animations occur simultaneously resulting in a very ugly and janky transition as two components are simultaneously both leaving and exiting.
My question is, how can I modify my code to ensure that only when one transition has completed can the next one start? I am happy to have the listener be disabled for the duration of the transition and only be re-enabled on a set timer (the time taken for the transition to complete ~ 0.8seconds).
Currently the event is able to fire as soon as the transition occurs, and I am unable to find a solution for it.
live working example below:
https://stackblitz.com/edit/react-ts-w42djd?embed=1&file=Hooks/useAppDirection.js
What I have tried:
I have tried a number of solutions with no success such as:
-creating variables to be true / false so that the if / else if statements only fire when the variable is true, but I can't engineer it in a way where it works (if I put it in the useEffect statement when the component changes Route it resets and does not have the desired effect)
- passing props to the component on transition
- played around with various minor tweaks
but nothing seems to work, I think there is something very fundamental I'm missing here but can't for the life of me work it out