I'm trying to create a smooth page transition using a combination of react-router-dom and framer-motion, and I'm trying to have my pages fade out on exit and fade in on enter. But exitBeforeEnter is not working how it's supposed to. The page will not fade out on exit but the next page will fade in every time. Below is my code, and I'll attach one of the page files (all of the pages have pretty much the same code).
Index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { BrowserRouter as Router } from "react-router-dom";
ReactDOM.render(<Router><App /></Router>, document.getElementById('root'));
App.js
import React from 'react';
import About from "./pages/About.js"
import Home from "./pages/Home.js"
import Projects from "./pages/Projects.js"
import { AnimatePresence } from 'framer-motion'
import { BrowserRouter as Switch, Route, useLocation } from "react-router-dom";
function App() {
const location = useLocation();
return (
<div className="App">
<AnimatePresence exitBeforeEnter>
<Switch location={location} key={location.pathname}>
<Route path="/about" component={About} />
<Route path="/projects" component={Projects} />
<Route path="/" exact component={Home} />
</Switch>
</AnimatePresence>
</div>
);
}
export default App;
Home.js (Page File)
import React from 'react';
import '../css/main.css';
import '../css/index.css';
import particleText from '../components/ParticleText.js'
import { Link } from 'react-router-dom';
import { motion } from 'framer-motion'
const pageVariants = {
in: {
opacity: 1,
transition: {
duration: 1
}
},
out: {
opacity: 0,
transition: {
duration: 1
}
}
}
class Home extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
try { particleText(true) } catch { /* Error */ }
return (
<motion.div className="main" initial="out" animate="in" exit="out" variants={pageVariants}>
<div className="introOverlay"></div>
<Link to="/about" className="homeButtonContainer">
<p className="homeButtonText">About Me</p>
</Link>
<Link to="/projects" className="homeButtonContainer">
<p className="homeButtonText">My Projects</p>
</Link>
</motion.div>
);
}
}
export default Home;
The property exitBeforeEnter
is deprecated now, it must be replaced with mode='wait'
:
<AnimatePresence mode='wait'>
...
<AnimatePresence>
That way, the change between components will be seamless since the first component will unmount before loading the next one with its respective animations.
Its a bit late but in case you still looking...
The exit
animation will NOT take place if AnimatePrecence
it self is unmounting from the react tree.
Try this in your App.js
:
return (
<Router>
<Route
render={ ({location}) => (
<AnimatePresence initial={ fase } exitBeforeEnter>
<Switch location={ location } key={ location.pathname }>
<Route
exact
path='/'
render={ () => <Home /> }
/>
<Route
exact
path='/projects'
render={ () => <Projects /> }
/>
<Route
exact
path='/about'
render={ () => <About/> }
/>
</Switch>
</AnimatePresence>
) }
/>
</Router>
);
You can leave the callback, render
for eg, I just include it for clarity.
The initial={false}
is just for disabling the initial animation for subsequent page reload;
If this doesn't work, make sure to keep the same variant structure the same in all your other components.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With