Jump to content
Search Community

React/Next - User Interrupted Scene Transitions

feralroo test
Moderator Tag

Recommended Posts

Demo: https://stackblitz.com/edit/nextjs-atnnzx?file=pages%2Findex.js

 

Hello,

 

I am working in React/Nextjs trying to create a component consisting of multiple scenes and tab-like buttons to switch between them. The components in each scene have in and out animations using opacity to create smooth fade transitions between each scene change. Due to the animations being triggered by user input it is highly likely they will be interrupted, so to help keep things smooth I've used.to on the out animations with the intention they animate out from whatever state they were before animating in the next scene.

 

I'll skip over my current understanding of why it currently isn't working as I'd hoped but at the moment when you click between the buttons and the active scene index changes,ctx.revert()gets called and the out animation animates out from a reset state so it's not smooth unless the in animation has completed. I've bashed my head against this for hours, I cannot work out how to approach this.

 

revert()needs to get called because otherwise I run into.from logic issues but I'm not sure at which place to call it. I've tried moving ctx.revert()to get called at the end of a timeline but that causes all sorts of confusion - I've a feeling I need multiple timelines and alternate between them during scene switches but am not sure how to implement and the stress of a deadline is causing my tiny brain to tighten up to the point I cannot think creatively.

 

I've created a minimal demo here with 3 scenes, and would really appreciate some help from the community: https://stackblitz.com/edit/nextjs-atnnzx?file=pages%2Findex.js

 

Here for any questions if I've not communicated my issue properly.

 

Thanks

Roo

 

 

 

Link to comment
Share on other sites

Hi @feralroo and welcome to the GSAP forums!

 

Unfortunately I don't have time right now to go through all your code (will circle back to it tomorrow).

 

What I think it could help in the mean time and the route I would go, is to use the add() method to add methods to the GSAP Context instance and perhaps create a more dynamic way to create those animations. Also keep in mind that creating and reverting that GSAP Context everytime the state of the component is updated, probably could be a source of a problem. Definitely create/revert the GSAP Context on an effect hook with an empty dependencies array, and just call a method when the state updates, something like this:

const ctx = useRef(); // store the GSAP Context in a ref

useEffect(() => {
  ctx.current = gsap.context((self) => {
    self.add("animateIn", (param) => {});
    self.add("animateOut", (param) => {});
  });
  return () => ctx.revert();
}, []);

useEfefct(() => {
  // Run your conditional logic here to decide which method call
  ctx.current.animateIn(activeScene);
  // or
  ctx.current.animateOut(activeScene);
}, [activeScene]);

 

Finally note that I used useEffect in both cases. I don't see the state update triggering any DOM changes, so I don't think a useLayoutEffect is needed, but you can keep using the useIsomorphicLayoutEffect hook without any issues.

 

Hopefully this helps.

Happy Tweening!

Link to comment
Share on other sites

Appreciate you taking the time to respond @Rodrigo, I wasn't aware of the ability to add to the context like that - reading about it now.

 

The below may be pretty hard to follow but I'll try my best:

I think my main issue is that I am relying on ctx.revert() to prevent me getting into .from logic errors on the animateOut() but of course it is also resetting the animation values on the element generated by the animateIn()so when the animateOut() interrupts the animateIn()rather than the .from making it a nice transition, it's doing .from the reverted/default values as defined by the css. I've unpacked what I'm doing wrong - I just can't crack a way to do it better and avoid those .from logic errors. I hope to hold on to the .from vs doing .fromTo as I want to be able to dynamically animate from whatever state the elements are in when a user clicks a new button and interrupts the animation.

 

Living in hope that someone clever might have encountered this before and can help get me unstuck!

 

Cheers,

Roo

Link to comment
Share on other sites

Hi,

 

Mainly the issue is that when the effect hook runs for the first time ctx.current is undefined:

useIsomorphicLayoutEffect(() => {
  if (prevActiveScene.current !== null) {
    tl.current.add(animateOut(prevActiveScene.current));
  }
  // The first time this runs ctx.current is still undefined
  ctx.current.animateIn(activeScene);

  prevActiveScene.current = activeScene;
}, [activeScene]);

Just adding a simple check for the context instance should solve that:

useIsomorphicLayoutEffect(() => {
  if (prevActiveScene.current !== null) {
    tl.current.add(animateOut(prevActiveScene.current));
  }
  ctx.current && ctx.current.animateIn(activeScene);

  prevActiveScene.current = activeScene;
}, [activeScene]);

Hopefully this helps.

Happy Tweening!

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...