Click here to Skip to main content
15,922,155 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
See more:
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
JavaScript
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
JavaScript
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
Posted
Updated 29-Dec-22 0:23am
Comments
0x01AA 29-Dec-22 7:54am    
Just a thought: How is about, to queue the events and process the queue sequential
Dave Kreskowiak 29-Dec-22 11:04am    
You have no way of "delaying" the raising of events your code did not originate. You can, however, change how you process them, like 0x01AA said, queue up the events you receive and process them one at a time in the order received.
Andre Oosthuizen 4-Jan-23 6:21am    
Possible with the onDone function, if one process is completed, do the next in stack - THIS has a working solution for you with little tweaking.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900