Motion: [BUG] AnimatePresence adds extra elements to the DOM

Created on 16 Apr 2020  路  12Comments  路  Source: framer/motion

Using AnimatePresence around a list render in React adds extra and duplicated DOM nodes.

In the picture above you can see that the react dev tools states I have 2 items in the array but it seems that AnimatePresence is exponentially adding dom nodes into the list

Link: https://codesandbox.io/s/lucid-germain-f2du3?file=/src/App.js
steps to replicate.

Steps to reproduce the behavior:

  1. Add an item
  2. It should be adding extra dom elements (this is the bug)
  3. If you remove AnimatePresence it doesn't add the extra dom elements but now I can't use AnimatePresence

Expected behavior

AnimatePresence should animate groups of elements on dom removal and additions.

6. Video or screenshots

Screen Shot 2020-04-16 at 11 02 06 AM

Screen Shot 2020-04-16 at 11 02 19 AM

ezgif com-video-to-gif
In this gif you can see that I have one item in the "cart" I click add item and AnimatePresence adds 2 elements. I quickly check my dev tools and validate that my react component is only showing two items with two different keys for them

7. Environment details

MacOS Catalina, Google Chrome latest

bug

All 12 comments

Hey Alexander, you are generating a new key for each item on every render. So the dom elements do not have a stable identity across renders. You see the same behaviour if you do not provide a key at all (but you get a nice warning).

Change key={uniqid()} to key={item}.

That solves the problem of the additional dom elements.

Adding an item works now but deleting does not. This could be a bug afterall.

Even if I change the key to the item (just noticed the key can be the item) it doesn't update the dom. I added a console.log() that logs the items on deleteItem and the Items in the dom still don't get updated.

https://codesandbox.io/s/lucid-germain-f2du3?file=/src/App.js

Is this being worked on? I currently need to use this for my work and really want to use framer-motion. Our current animations are being stalled because of this bug.

Is there a beta or a less stable package that I can use that maybe fixes this issue?

Is this being worked on? I currently need to use this for my work and really want to use framer-motion. Our current animations are being stalled because of this bug.

Is there a beta or a less stable package that I can use that maybe fixes this issue?

Is this being worked on? I currently need to use this for my work and really want to use framer-motion. Our current animations are being stalled because of this bug.

Is there a beta or a less stable package that I can use that maybe fixes this issue?

try this

https://codesandbox.io/s/new-browser-oiv4p?file=/src/App.js

@AlexanderMelox I just change the wrapper motion.div to a simple div and i moved

initial="enter" animate="open" exit="close"

to the inner element

<div className="list"> <AnimatePresence> {items.map(item => ( <motion.div variants={variants} initial="enter" animate="open" exit="close" key={item} className="list-item"> item: {item} <button onClick={() => deleteItem(item)}>&times;</button> </motion.div> ))} </AnimatePresence> </div>

@dna1986 This works! I am just confused because the creator of framer-motion did it the way that I did it so is this definitely a bug? or a workaround

@AlexanderMelox As reported in this Page (For me the reference page) https://www.framer.com/api/motion/animate-presence/
AnimatePresence must wrap one or more motion components to works correctly

@dna1986 This works! I am just confused because the creator of framer-motion did it the way that I did it so is this definitely a bug? or a workaround

It's intended behaviour. The children of AnimatePresence must have exit props, not the parent.

Wouldn't the variant pick up the exit prop from the Parent tree?

<motion.div initial="enter" animate="open" exit="close" className="list">
        <AnimatePresence>
          {items.map(item => (
            <motion.div variants={variants} key={item} className="list-item">
              item: {item}
              <button onClick={() => deleteItem(item)}>&times;</button>
            </motion.div>
          ))}
        </AnimatePresence>
      </motion.div>

No - the component that has animate/initial/exit defined will trigger these animations down throughout the tree. The parent component never exits, so it will never fire an exit animation down the tree.

So to iterate. If AnimatePresence has a parent that controls an orchestration and it has the exit prop, it does not get inherited by the children of AnimatePresence. Is that correct?

I'm trying to get this right haha, I'm pushing real hard at IBM for our devs to start using Framer motion as the package for animation. I'm also doing a lightning talk on it so I would want to be 100% correct on this.

Correct. It's not the keys (initial/animate/exit) that get inherited. The components these are defined on are the components that trigger those animations down the tree. Which is how options like staggerChildren make sense.

Okay, thanks I guess we can close this issue then?

Was this page helpful?
0 / 5 - 0 ratings