Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

exitBeforeEnter is not working as intended - Trouble w/ Page Transitions

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;
like image 218
Sterling Velazquez Avatar asked Sep 15 '25 22:09

Sterling Velazquez


2 Answers

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.

like image 63
Emanuel Romano Avatar answered Sep 17 '25 14:09

Emanuel Romano


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.

like image 25
ObinasBaba Avatar answered Sep 17 '25 14:09

ObinasBaba