Search code examples
reactjsreact-spring

DOM element won't get removed on react spring animation


I'm working on a tutorial and i'm having an issue after adding react spring transition on the checkout page handled by Checkout.js component.

My problem happens when removing items from the basket, the last item on the basket never remove from the DOM even when the array removed the element via reducer.

This was working as expected before adding a transition and animated.div element to checkout component below.

import React from "react";
import "./Checkout.css";
import SubTotal from "./SubTotal";
import { useStateValue } from "../StateProvider";
import CheckoutProduct from "./CheckoutProduct";
import shortid from "shortid";

import { useTransition, animated } from "react-spring";

function Checkout() {
  const [{ basket, user }] = useStateValue();

  const getRandomKey = () => {
    return shortid.generate();
  };

  // define transition behaviour
  const transition = useTransition(basket, basket => basket.id, {
    from: { opacity: 0, marginLeft: -100, marginRight: 100 },
    enter: { opacity: 1, marginLeft: 0, marginRight: 0 }
  });

  return (
    <div className="checkout">
      <div className="checkout__left">
        <img
          className="checkout__ad"
          src="https://images-na.ssl-images-amazon.com/images/G/02/UK_CCMP/TM/OCC_Amazon1._CB423492668.jpg"
          alt=""
        ></img>
        <div className="checkout__title">
          <h3>Hello, {user?.email}</h3>
          <h2>Your shopping basket</h2>
          {transition.map(({ item, key, props }) => {
            const keyNew = getRandomKey();
            console.log(keyNew + "this is the new key");
            return (
              <animated.div
                key={keyNew}
                style={props}
                className="checkout__product"
              >
                <CheckoutProduct
                  id={item.id}
                  image={item.image}
                  price={item.price}
                  rating={item.rating}
                  title={item.title}
                />
              </animated.div>
            );
          })}
        </div>
      </div>

      <div className="checkout__right">
        <h2>SubTotal component</h2>
        <SubTotal />
      </div>
    </div>
  );
}

export default Checkout;

Steps to reproduce: Add any product to the basket click on basket icon to go to checkout screen and try to remove items

Here is the github repo with the tutorial code i'm working on.

Is this problem that requires me to force a render?

Thanks

Solution:

Upgraded react spring dependency from 8.0.27 to 9.0.0-rc.3 as suggested by Peter's reply.

And refactored the component as follows us:

import React from "react";
import "./Checkout.css";
import SubTotal from "./SubTotal";
import { useStateValue } from "../StateProvider";
import CheckoutProduct from "./CheckoutProduct";
import shortid from "shortid";
import { useTransition, animated } from "react-spring";

function Checkout() {
  const [{ basket, user }] = useStateValue();

  const getRandomKey = () => {
    return shortid.generate();
  };

  // define transition behaviour
  const transition = useTransition(basket, {
    from: { opacity: 0, marginLeft: -100, marginRight: 100 },
    enter: { opacity: 1, marginLeft: 0, marginRight: 0 }
  });

  return (
    <div className="checkout">
      <div className="checkout__left">
        <img
          className="checkout__ad"
          src="https://images-na.ssl-images-amazon.com/images/G/02/UK_CCMP/TM/OCC_Amazon1._CB423492668.jpg"
          alt=""
        ></img>
        <div className="checkout__title">
          <h3>Hello, {user?.email}</h3>
          <h2>Your shopping basket</h2>
          {transition((props, item) => {
            const keyNew = getRandomKey();
            return (
              <animated.div style={props}>
                <CheckoutProduct
                  key={keyNew}
                  id={item.id}
                  image={item.image}
                  price={item.price}
                  rating={item.rating}
                  title={item.title}
                />
              </animated.div>
            );
          })}
        </div>
      </div>

      <div className="checkout__right">
        <h2>SubTotal component</h2>
        <SubTotal />
      </div>
    </div>
  );
}

export default Checkout;

Solution

  • Have you tried with the original key? If you change the key handling strange things can happen.

          {transition.map(({ item, key, props }) => {
            return (
              <animated.div
                key={key}
                style={props}
                className="checkout__product"
              >
           ....
    

    Update:

    Also there are some bugs with transition. Try to raise the version number. You can try around 9.0.0-beta.4 or slightly higher. Or you can try 9.0.0-rc.3, but it has a slightly different api. Check the documentation here: https://aleclarson.github.io/react-spring/v9/#Revamped-types