Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Delayed visualElement subscription can miss animations in using LazyMotion #2292

Closed
gurkerl83 opened this issue Aug 11, 2023 · 1 comment · May be fixed by #2293
Closed

Delayed visualElement subscription can miss animations in using LazyMotion #2292

gurkerl83 opened this issue Aug 11, 2023 · 1 comment · May be fixed by #2293
Labels
bug Something isn't working wontfix This will not be worked on

Comments

@gurkerl83
Copy link

gurkerl83 commented Aug 11, 2023

When utilizing the LazyMotion component, there's a scenario where the visualElement might not be immediately available for the animation controls. In the original animationControls code, animations get started without ensuring the presence of any subscribed visualElement, potentially causing missed animations.

Steps to reproduce:

  • Integrate the LazyMotion component into a project.
  • Use m-Components.
  • Call controls.start() before the visualElement has subscribed - in the effect.
  • Observe that animations may be skipped or missed.
Lazy-Load.ts
export { domAnimation as default } from 'framer-motion';
import { m, LazyMotion, useAnimation, useMotionValue } from 'framer-motion';
import { FC, useEffect } from 'react';

// only way to keep bundle size small
const loadFeaturesAsync = async () =>
  await import('./Lazy-Load').then(res => res.default);

// it works when features are loaded synchronously like, but bundle size increases
// import { domAnimation } from 'framer-motion';
// <LazyMotion features={domAnimation}>

export const AnimationTest: FC = () => {
  const controls = useAnimation();

  const variants = {
    foo: { x: 100 }
  };

  const childVariants = {
    foo: { backgroundColor: '#fff' }
  };

  const x = useMotionValue(0);
  const backgroundColor = useMotionValue('#000');

  useEffect(() => {
    controls.start('foo').then(() => {
      console.log('variants result: ', [x.get(), backgroundColor.get()]);
    });
  }, []);

  return (
    <LazyMotion features={loadFeaturesAsync}>
      <m.div
        animate={controls}
        variants={variants}
        style={{ x }}
        onAnimationStart={() => {
          console.log('onAnimationStart outer');
        }}
        onAnimationComplete={() => {
          console.log('onAnimationComplete outer');
        }}
      >
        <m.div
          variants={childVariants}
          style={{ backgroundColor }}
          onAnimationStart={() => {
            console.log('onAnimationStart inner');
          }}
          onAnimationComplete={() => {
            console.log('onAnimationComplete inner');
          }}
        >
          Hello
        </m.div>
      </m.div>
    </LazyMotion>
  );
};

Here is the sandbox https://codesandbox.io/p/sandbox/polished-sunset-pg25zr

Expected Behavior:
Animations should always be played regardless of when the visualElement subscribes.

Actual Behavior:
Animations might be skipped if started before the visualElement subscription.

Suggested Fix:
Improve animationControls to queue animation start calls and processes them once the visual element is available, see referenced PR

@gurkerl83 gurkerl83 added the bug Something isn't working label Aug 11, 2023
gurkerl83 pushed a commit to gurkerl83/motion that referenced this issue Aug 11, 2023
What's changed?
This pull request introduces changes to the animationControls function to handle scenarios where the visualElement might not immediately subscribe, especially in the context of the LazyMotion component.

Introduced Start Queue: An array that temporarily holds animation start calls. This ensures animations are deferred until their respective visual elements have subscribed to the animation controller.

Flush Mechanism: Once a visualElement subscribes, any queued animations are immediately processed and played.

Error Handling: Added robust error handling to cater to potential issues during the animation process. This ensures promises are either resolved upon successful completion or rejected in case of errors.

Benefits:
This change ensures animations are consistently played in scenarios involving delayed visualElement subscriptions, enhancing user experience and ensuring predictable behavior.

How to test:

Integrate the LazyMotion component, described in framer#2292

- Integrate the LazyMotion component into a project.
- Import features dynamically to keep bundle size small.
- Use m-Components.
- Call controls.start() before the visualElement has subscribed - in the effect.

Ensure that animations play consistently, irrespective of when the controls.start() is called in relation to the visualElement subscription.
@mattgperry
Copy link
Collaborator

Because useAnimation is deprecated in favour of useAnimate I'm probably not going to have the time to fix this so closing as wontfix to set expectations

@mattgperry mattgperry added the wontfix This will not be worked on label Jan 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working wontfix This will not be worked on
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants