React Spring useTransition rendering issue with dubplicate digits

43 views Asked by At

I am using the useTransition hook from React Spring to animate an array of strings stored in an usestate.

The animation removes and vertically scrolls each digit, but when the array contains duplicate digits it removes and adds elements twice.

const [lista, setLis] = useState(['5', '0']);

const hour = useTransition(lista, {
  from: { opacity: 0, y: -50 },
  enter: { opacity: 1, y: 0 },
  leave: { opacity: 0, y: 50 },
  exitBeforeEnter: true,
  config: { duration: 400 },
});

{hour((style, cont) => (
  <animated.div style={style}>
    <h2 className="mb-0 text-warning" style={style}>
      {cont}
    </h2>
  </animated.div>
))}

I am aware this is due to how useTransition handles updates, but is there any way to bypass this without needing to have a single useTransition for each digit?

Complete example Here

1

There are 1 answers

1
Łukasz D. Mastalerz On

Try this, I'm not 100% sure if you were talking about this solution, but it seems logical to me.

import React, { useState, useEffect } from 'react';
import './style.css';
import { useTransition, animated } from '@react-spring/web';
import 'bootstrap/dist/css/bootstrap.css';

function App() {
  const [time1, setTime1] = useState(0);
  const [time2, setTime2] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      setTime1(prevTime1 => {
        if (prevTime1 === 9) {
          setTime2(prevTime2 => prevTime2 + 0.5);
          return 0;
        } else {
          return prevTime1 + 1;
        }
      });
    }, 1000);

    return () => clearInterval(interval);
  }, []);

  const hour1 = useTransition(time1, {
    from: { opacity: 0, y: -50 },
    enter: { opacity: 1, y: 0 },
    leave: { opacity: 0, y: 50 },
    exitBeforeEnter: true,
    config: { duration: 400 },
    unique: true,
  });

  const hour2 = useTransition(time2, {
    from: { opacity: 0, y: -50 },
    enter: { opacity: 1, y: 0 },
    leave: { opacity: 0, y: 50 },
    exitBeforeEnter: true,
    config: { duration: 400 },
    unique: true,
  });

  return (
    <div>
      <div className="d-flex justify-content-center align-items-center">
        <div className="row mx-0 col-10">
          <div className="col-6 d-flex justify-content-center align-items-center">
            <div className="row mx-0">
              {hour1((style, cont) => (
                <animated.div
                  className="col-6 d-flex justify-content-center align-items-center bg-danger border border-2 border-warning h-100"
                  style={style}
                  key={cont}
                >
                  <h2 className="mb-0 text-warning">{cont}</h2>
                </animated.div>
              ))}
            </div>
          </div>
          <div className="col-6 d-flex justify-content-center align-items-center">
            <div className="row mx-0">
              {hour2((style, cont) => (
                <animated.div
                  className="col-6 d-flex justify-content-center align-items-center bg-danger border border-2 border-warning h-100"
                  style={style}
                  key={cont}
                >
                  <h2 className="mb-0 text-warning">{cont}</h2>
                </animated.div>
              ))}
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

export default App;