Search code examples
reactjsanimationframer-motion

AnimatePresence show both elements when animating


I am to make a step-like animation, hence, when I click a button, another div than the previous is shown, e.g:

import { motion, AnimatePresence } from 'framer-motion'

const MyApp= props => {
  const [count, setCount] = useState(0)

  return (
    <>
      <AnimatePresence>
        {count == 0 && (
          <motion.div
            transition={{ duration: 2 }}
            initial={{ opacity: 1 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
          >
            Hello 1
            <button onClick={() => { setCount(count + 1) }}
          </motion.div>
        )}
      </AnimatePresence>
      <AnimatePresence>
        {count == 1 && (
          <motion.div
            transition={{ duration: 2 }}
            initial={{ opacity: 1 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
          >
            Hello 2
            <button onClick={() => { setCount(count + 1) }}
          </motion.div>
        )}
      </AnimatePresence>
    </>
  )
}

export default MyApp

However, the issue is, that when one div is fading out/in, the other is also fading in/out, hence, I have two elements at the same time. Instead I thought it would just animate one, remove it, and animate the other.

Am I doing something wrong here ?


Solution

    1. Since you want to animate them together they should be under one <AnimatePresence />
    2. AnimatePresence requires you to add an explicit key on the component you are animating beneath it so that it can track the components as they are added and removed https://www.framer.com/api/motion/animate-presence/#unmount-animations
    3. Since you want to replace one component with another you need to add the prop exitBeforeEnter on the AnimatePrensence. https://www.framer.com/api/motion/animate-presence/#animatepresenceprops.exitbeforeenter
            <AnimatePresence exitBeforeEnter> // Note on #3
              {isGreenBox ? (// Note on #1
                <GreenBox
                  initial={{ scale: 0 }}
                  animate={{ scale: 1 }}
                  exit={{ scale: 0 }}
                  key="green" // Note on #2
                />
              ) : (
                <PurpleBox
                  initial={{ scale: 0 }}
                  animate={{ scale: 1 }}
                  exit={{ scale: 0 }}
                  key="purple" // Note on #2
                />
              )}
            </AnimatePresence>
    

    Here is a working example I created :) https://codesandbox.io/s/framer-motion-animation-presence-exitbeforeenter-0miq0