2

I've currently made a carousel component, I'm passing my data to it but I would like to add a transition between switching the data.

I've heard a lot of people recommending react-spring so I thought I'd give it a try. I'm currently trying to implement the useTransition hook, but it's not working as desired.

I simply want to fade in/out only the data when the user presses the "left" / "right" buttons. Currently it starts to fade my content, but then creates a clone of my carousel, and doesn't fade... I'm not sure what I'm doing wrong or if this is the correct hook I should be using?

Ultimately I would prefer a stagger animation when the content fades in with some delay between each element. For example: the title, then price, then desciption, etc, would fade in but with a 300ms delay between each element.

Here's what I currently have:

const mod = (n: any, m: any) => ((n % m) + m) % m;

const CarouselContainer: React.FC = () => {
  const [index, setIndex] = useState(0);

  const handlePrev = useCallback(() => {
    setIndex(state => mod(state - 1, data.length));
  }, [setIndex]);

  const handleNext = useCallback(() => {
    setIndex(state => mod(state + 1, data.length));
  }, [setIndex]);

  const transitions = useTransition([index], (item: number) => item, {
    from: { opacity: 0 },
    enter: { opacity: 1 },
    leave: { opacity: 0 }
  });

  return (
    <>
      {transitions.map(({ item, props, key }) => (
        <Carousel
          prevClick={handlePrev}
          icon={data[item].icon}
          title={data[item].title}
          price={data[item].price}
          description={data[item].description}
          href={data[item].href}
          nextClick={handleNext}
          style={props}
          key={key}
        />
      ))}
    </>
  );
};

There's quite a lot of code so I'm providing a CodeSandBox, forks are appretiated! :)

Jordan
  • 1,101
  • 1
  • 12
  • 26

1 Answers1

1

When the mount and unmount happens during the transition, there is a moment when the new and the old element is in the dom simultaneously. Most of the time I use absolute positioning with transition for this reason. This way the change blend in well.

For this you have to change to position: absolute here:

const StyledWrapper = styled.div`
  position: absolute;
  display: grid;
  grid-template-columns: auto auto 20% 20% 1fr auto auto;
  grid-template-rows: 3em 1fr auto 1fr 3em;
  grid-gap: 0;
`;

I would try to add some movement to it:

  const transitions = useTransition([index], (item: number) => item, {
    from: { opacity: 0, transform: 'translateX(-420px)' },
    enter: { opacity: 1, transform: 'translateX(0px)' },
    leave: { opacity: 0, transform: 'translateX(420px)' }
  });

And here is your modified code: https://codesandbox.io/s/empty-rgb-xwqh1

Next you will want to handle the direction of the movement, according to the button pressed. Here is an example for that: https://codesandbox.io/s/image-carousel-with-react-spring-usetransition-q1ndd

Peter Ambruzs
  • 7,763
  • 3
  • 30
  • 36
  • Isn''t there a way of just transitioning the content instead of the entire carousel? Also it's not completely fading the content out and then back in though? I tried adding a duration `config: { duration: 1000 }`, but it fades back in before it's finished fading out? – Jordan Apr 15 '20 at 15:28
  • You can put the animation to whatever div you want. It can be inside the carousel if you feel like. I added a little movement to the pages, this way you can follow better what is going on. I updated my answer. – Peter Ambruzs Apr 16 '20 at 06:08
  • Hi @Jordan. Did you solve this? I have the same problem than you. It starts making the fading and then it finishes it without smooth transition. – Rogar Mar 06 '21 at 02:12