Seanyboy Lee
Seanyboy Lee

Reputation: 195

useTransition in React Spring causes too many rerenders

I'm using useTransition from react spring to build a masonry-gridish display of animated words for a blog. My work is heavily based on react spring's official codesandbox demo of a masonry grid which can be found here: https://codesandbox.io/embed/26mjowzpr

My work can be found here: https://codesandbox.io/s/qrzn-issue-2-david-byrne-8s7bo?file=/src/App.js:1267-1293

What you'll notice in my codesandbox, is that if you click on one of the little heads on the bottom, the transition occurs, but then the page will rerender about 20 times and I can't figure out why.

I think it has something to do with my invocation of useTransition, but am totally at a loss

  const leftTransitions = useTransition(leftGridItems, item => item.word, {
    from: ({ xy, width, height }) => {
      return {
        xy: [xOffset, yOffset],
        width,
        height,
        opacity: 0
      };
    },
    enter: ({ xy, width, height }) => ({ xy, width, height, opacity: 1 }),
    update: ({ xy, width, height }) => ({ xy, width, height }),
    leave: ({ xy, width, height }) => {
      return {
        xy: [xOffset, yOffset],
        opacity: 0
      };
    },
    config: { mass: 5, tension: 500, friction: 100 },
    trail: 25
  });

Upvotes: 0

Views: 645

Answers (2)

Dwiyan Putra
Dwiyan Putra

Reputation: 1

me fixed by adding overflow (in this case i'm using tailwind so i'm just using overflow-x-scroll with max-w-full. Here's the sample

        <div
          className={cn(
            "w-full max-w-full disable-scrollbars overflow-x-scroll h-full flex flex-row justify-between phonewide:justify-between items-center",
            "tansition-all duration-300 ease-in-out"
          )}
        >
          <ChevronLeft
            className="phonewide:flex sm:flex lg:w-16 lg:h-16 md:w-10 md:h-10 sm:h-7 sm:w-7 w-7 h-7 text-gray-500"
            onClick={() => {
              setDirection("left");
              if (idx === 0) {
                setIdx(DUM_BATTERY.length - 1);
                return;
              }
              setIdx((state) => (state - 1) % 4);
            }}
          />
          {transitions((style, item, ts) => (
            <animated.div
              key={item.id}
              className={cn(
                "phonewide:space-x-5 sm:space-x-5 space-x-2 lg:space-x-10",
                "flex flex-col items-center justify-center",
                "phonewide:flex-row md:flex-row sm:flex-row",
                "transition-all duration-700 ease-in-out"
              )}
              style={{
                ...style,
                width: "100%",
              }}
            >
              <div>
                <Image
                  src={getBatteryImage(item?.battery?.picture)}
                  width={200}
                  height={220}
                  alt="Battery image"
                  className="rounded-lg h-28 w-28 sm:h-60 sm:w-60 lg:h-72"
                />
              </div>
              <div className="flex flex-col justify-between">
                <div>
                  <p className="text-lg lg:text-xl font-semibold mt-4 sm:mt-0">
                    {item.name}
                  </p>
                  <p className="text-base text-gray-500">
                    Capacity: {batteryMeta.capacity} kWh
                  </p>
                  <p className="text-base text-gray-500">
                    Warranty: {batteryMeta.warranty} Years
                  </p>
                </div>
                {/* desktop view */}
                <div className="flex-col space-y-2 mt-2 w-full hidden sm:flex">
                  <div className="flex items-center justify-between phonewide:justify-center space-x-4 bg-gray-100 rounded-lg px-4 py-2 phonewide:w-min w-full">
                    <button className="text-xl font-semibold text-gray-600">
                      -
                    </button>
                    <span className="text-xl font-medium text-gray-800">1</span>
                    <button className="text-xl font-semibold text-gray-600">
                      +
                    </button>
                  </div>
                  <Button>Select Battery</Button>
                </div>
              </div>
            </animated.div>
          ))}
          <ChevronRight
            className="phonewide:flex sm:flex lg:w-16 lg:h-16 md:w-10 md:h-10 sm:h-7 sm:w-7 w-7 h-7 text-gray-500"
            onClick={() => {
              setDirection("right");
              if (idx === DUM_BATTERY.length - 1) {
                setIdx(0);
                return;
              }
              setIdx((state) => (state + 1) % 4);
            }}
          />
        </div>

The config:

  const [direction, setDirection] = React.useState("right");
  const [idx, setIdx] = React.useState(0);

  const transitions = useTransition(DUM_BATTERY[idx], {
    from: {
      opacity: 0,
      transform:
        direction === "left" ? "translateX(-100%)" : "translateX(100%)",
    },
    enter: { opacity: 1, transform: "translateX(0%)" },
    leave: {
      opacity: 0,
      transform:
        direction === "left" ? "translateX(100%)" : "translateX(-100%)",
    },
    config: {
      ...config.wobbly,
      duration: 700,
    },
    reset: true,
    exitBeforeEnter: true,
  });

Upvotes: 0

Seanyboy Lee
Seanyboy Lee

Reputation: 195

If anyone's interested, this is no longer an issue if you update to v9. Details in the changelog here: https://www.react-spring.io/log

Upvotes: 0

Related Questions