Search code examples
javascriptreactjstypescriptframer-motion

Removing from list causes initial animation to play when map returns a component


Would someone please explain to me why this issue is happening? I have an array of objects that are mapped, and fade in when added to the array.

If inside the map, I return the actual jsx code for the object, then when the object is removed from the array it animates the remaining cards like it should.

{cards.map((c) => {
    return (
        <motion.div
            key={key}
            variants={variant}
            layout}
        >
        ...ETC
        </motion.div>
    );
})}

However, if inside the map I use a separate component instead, it does not animate and instead causes all of the objects after the removed object to fade in the opacity again.

{cards.map((c) => {
    return <Card data={card} />;
})}

You can see a comparison here (click to remove card)
Map returning JSX code (works): https://codesandbox.io/s/crimson-http-qtpi0
Map returning component (does not work): https://codesandbox.io/s/romantic-dewdney-dfqlp

I'm not the most educated person about React. Would anyone be able to point me in the right direction for solving this issue? Thank you.


Solution

  • When you return a list of elements like that, each one needs to have a unique key prop. That way when the list changes, React can identify which elements changed. (You could potentially have multiple elements with the same data.)

    In fact, if you look in the console of your second example there's an error telling you precisely that:

    Warning: Each child in a list should have a unique "key" prop.

    To fix it, add a unique key prop to the <Card> elements, like you have in your first example.

    I'm not sure if your npa or npx values are guaranteed to be unique. If not, you can add an id field to the data.

    {cards.map((c) => {
        return <Card data={card} key={c.id} />;
    })}