I'm trying to animate some elements based on weather the user is progressing forward or backward. e.g. state > prevState
or state < prevState
Here is what the logic looks like.
-Hook to update state and track previous state
import { useState } from "react";
export default function useStateWithPrevious(initial) {
const [value, setValue] = useState(initial);
const [prev, setPrev] = useState(initial);
function setValueAndPrev(newValue) {
if (newValue === value) return; // optional, depends on the logic you want.
setPrev(value);
setValue(newValue);
}
return [prev, value, setValueAndPrev];
}
Hook use
const [previousRegistrationDay, registrationDay, setRegistrationDay] = useSetDayWithPreviousDay(1);
Here is the Framer Motion Component.
<AnimatePresence mode="wait">
<motion.nav
key={registrationDay}
animate={{ x: "0%", opacity: 1 }}
transition={{ duration: 0.5 }}
initial={{ opacity: 0, x: previousRegistrationDay < registrationDay ? "100%" : "-100%" }}
exit={{ opacity: 0, x: previousRegistrationDay < registrationDay ? "-100%" : "100%" }}
>
<div>
registrationDay{registrationDay}
<br />
previousRegistrationDay{previousRegistrationDay}
</div>
</motion.nav>
</AnimatePresence>
Example https://youtu.be/lmob3oJUgkA
This works for the most part, but the first time you "go back" / "change directions" the animation exit is wrong.
It's like there is a closure around the variables defining the exit transition, causing it to be wrong the first time the prevState > state
and then switching to prevState < state
Any help is greatly appreciated!
What you need is variants with custom argument and custom prop of AnimatePresence.
You define your animations as variant which accepts custom argument (direction in your case) and depending on it returns desired properties. Then you need to pass direction as custom
prop to both your component (to make appear animation work correctly) and to AnimatePresence to make exit animation aware of direction too.
Here is example how it's implemented in my project:
UPD: I wrote an article about this with examples in my blog.