Dylan Bozarth
Dylan Bozarth

Reputation: 1694

Exit animations in react framer-motion not appearing

I am creating a space viewer app and using Framer motion for the animations. What I am aiming for is the starting component that is called loading will have an exit animation upon being clicked. However at the moment all of my components are failing to have exit animations. They simply lead to other components as if I was only using react-router.

My app.js looks like this

<AnimatePresence  /* I have tried to put exitBeforeEnter here, it does nothing*/ >
<Route exact path="/" key="loading"  component={Loading} />
            <Route  path="/sol" key="menu"  component={Menu} />

And my loading component looks like this

 const loading = {
        start: {
         scale: 2,
       
        },
        out: {
          scale: .1,
        
        },
      };
      const pagetransition = {
        duration: 2,
      };
    return(
    <motion.div initial="start"
    animate="in"
   exit="out"
    variants={loading}
    transition={pagetransition}    className="loadingScreen"
    >
<NavLink to="/sol"><button ><p >Enter System</p></button></NavLink>
    </motion.div>

At the moment, none of my pages have exit animations, but they do have entrance animations, so I know that I am not doing things totally wrong. I have a codesandbox where all of my code is visible.

Upvotes: 2

Views: 4024

Answers (1)

Riptide
Riptide

Reputation: 516

I have made some changes in the code sandbox. Using Framer-Motion to do route transitions is quite easy but a little involved. First you have to use AnimatePresence outside the <Switch> ... </Switch>. Then you need to have some key in Switch for Framer-motion to keep track of the routes.

We use location for the key and inorder to use the useLocation() hook in App.js, we'll need to surround <App /> in index.js with Router. So that's what I've done.

Here are the changes that I've explained until now.

In index.js

import { BrowserRouter as Router } from "react-router-dom";

ReactDOM.render(
  <React.StrictMode>
    <Router>
      <App />
    </Router>
  </React.StrictMode>,
  document.getElementById("root")
);

In App.js

import { Switch, Route, useLocation } from "react-router-dom";
import { AnimatePresence, motion } from "framer-motion";

function App() {
  const location = useLocation();
  return (
    <AnimatePresence>
      <Switch location={location} key={location.pathname}>
        // all the routes here
      </Switch>
    </AnimatePresence>
  );
}

Then in loading.js, surround the entire thing with a motion.div. This motion.div is what will animate. I've done a simple left to right for entering, and right to left for exit.

Changes made in loading.js

  const routeTransition = {
    hide: {
      x: "100vw"
    },

    animate: {
      x: 0,
      transition: {
        delay: 0.75,
        duration: 0.75,
        when: "beforeChildren",
        staggerChildren: 0.5
      }
    },

    exit: {
      x: "-100vw",
      transition: {
        duration: 0.75
      }
    }
  };

return (

    <motion.div // this is the div that will animate the entire route
      variants={routeTransition}
      initial="hide"
      animate="animate"
      exit="exit"
    > 
      <motion.div // this div will only animate the button
        initial={{ opacity: 0 }}
        animate={{ opacity: 1 }}
        exit={{ opacity: 0 }}
        transition={pagetransition}
        className="loadingScreen"
      >
        <NavLink to="/sol">
          <button>
            <p>Enter System</p>
          </button>
        </NavLink>
      </motion.div>
    </motion.div>
  );

Upvotes: 1

Related Questions