First, define some animations:
const InitialOffset = 64;
export const variants = {
enterFromRight: {
enter: { translateX: InitialOffset, opacity: 0 },
visible: { translateX: 0, opacity: 1 },
},
enterFromLeft: {
enter: { translateX: -InitialOffset, opacity: 0 },
visible: { translateX: 0, opacity: 1 },
},
enterFromTop: {
enter: { translateY: -InitialOffset, opacity: 0 },
visible: { translateY: 0, opacity: 1 },
},
};
then at the root of your application, add a listener to react-router-dom's history object:
const App = () => {
// Create our list of recent paths based on our initial location
const history = useHistory();
const location = useLocation();
const [recentPaths, setRecentPaths] = useState([location.pathname]);
// Assign a listener to react-router-dom's 'history' object so that we can track recently visited pages
useEffect(() => {
history.listen((route) => setRecentPaths((recentPaths) => [route.pathname, ...recentPaths].slice(0, MaxHistory)));
}, []); // eslint-disable-line react-hooks/exhaustive-deps
return <main>{/* Children here */}</main>;
};
finally, at a page level, consume the recent paths via a context and choose your page transition based on the previous page:
const Page = () => {
const recentHistory = useContext(RecentHistoryContext);
const previousRoute = recentHistory[1];
let variant = variants.enterFromTop;
if (previousRoute === "/page-1") variant = variants.enterFromRight;
if (previousRoute === "/page-3") variant = variants.enterFromLeft;
return (
<motion.div variants={variant} initial="enter" animate="visible">
{/* Page content here */}
</motion.div>
);
};