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

[BUG] AnimatePresence gets stuck when state changes quickly #2554

Closed
tommhuth opened this issue Mar 13, 2024 · 51 comments · Fixed by #2741
Closed

[BUG] AnimatePresence gets stuck when state changes quickly #2554

tommhuth opened this issue Mar 13, 2024 · 51 comments · Fixed by #2741
Labels
bug Something isn't working

Comments

@tommhuth
Copy link

tommhuth commented Mar 13, 2024

2. Describe the bug
Framer Motion v11.0.12: When state changes very quickly AnimatePresence gets stuck and out of sync and no longer removes the element but instead always animates it in. Reverting to version v10.12.2 (based of other bug report concerning a similar/same issue) does not exhibit the same problem

3. IMPORTANT: Provide a CodeSandbox reproduction of the bug
https://codesandbox.io/p/sandbox/serene-brattain-qwd278

4. Steps to reproduce

  1. Conditionally render an element inside AnimatePresence with an exit animation
  2. Trigger condition change quickly
  3. Animating component gets stuck as rendered, and any changes to the condition will just trigger an reset from initial => animate. The component is no stuck as visible and will never leave the DOM.

5. Expected behavior

The component should not get stuck as mounted

6. Video or screenshots

If applicable, add a video or screenshots to help explain the bug.

7. Environment details

Chrome 122, Mac Sonoma

@tommhuth tommhuth added the bug Something isn't working label Mar 13, 2024
@Roon311
Copy link

Roon311 commented Mar 14, 2024

I am encountering the same issue
When the state changes quickly resolved changes to undefined.

3fcf8351-a7be-482b-8864-c3eb0dc729f1

@mattgperry
Copy link
Collaborator

Thanks for the sandbox - are you able to set it to public so I can take a look?

@Roon311
Copy link

Roon311 commented Mar 14, 2024

@mattgperry When you use the right arrown to navigate through the animating images, the error shows up

@notmedia
Copy link

notmedia commented Mar 14, 2024

@Roon311 your link is also unavailable

Unable to access this workspace
It is likely that you are not a member of the team that this project belongs to. To be able to access the web editor of this repository and edit the code, you need to be invited to the team.

@justrealmilk
Copy link

justrealmilk commented Mar 14, 2024

Okay now that I know why it breaks I can actually trigger the problem https://codesandbox.io/p/sandbox/modern-wood-h35hc6

Click page/back until it breaks I guess

@Roon311
Copy link

Roon311 commented Mar 14, 2024

@notmedia It should be working now.
if you keep pressing the right arrow you will get the error.

@OlegWock
Copy link

OlegWock commented Mar 17, 2024

Here is another reproduction. Double click the button to see it

https://stackblitz.com/edit/framer-motion-animate-presence-bug?file=src%2FHoldToConfirm.tsx

I can confirm that framer motion 11.0.8 works correctly with same code

@tommhuth
Copy link
Author

sorry about that, https://codesandbox.io/p/sandbox/serene-brattain-qwd278 is now public

@eryilmazyasin
Copy link

eryilmazyasin commented Mar 20, 2024

I have the same problem and still could not find the solution. It happened after version 11.0.8. Here is my example and code below.

      <AnimatePresence>
                    {open && (
                        <motion.div
                            key="contentMarkContainer"
                            initial={{ opacity: 0, position: 'absolute', bottom: 0, left: 0, right: 0 }}
                            animate={{ opacity: 1 }}
                            exit={{ opacity: 0, transition: { ease: 'easeOut', duration: 0.75 } }}
                        >
                            {My codes here...}
                         </motion.div>
                         )}
        </AnimatePresence>
Screen.Recording.2024-03-20.at.13.53.11.mov

@iravid
Copy link

iravid commented Mar 26, 2024

This appears to have been broken in 11.0.11. Last version that doesn't suffer from this issue is 11.0.10.

@ConsoleTVs
Copy link

This appears to have been broken in 11.0.11. Last version that doesn't suffer from this issue is 11.0.10.

Correct. Just checked!

@federicocappellotto97
Copy link

Same here, using "framer-motion": "^11.0.25"

@HHogg
Copy link

HHogg commented Apr 11, 2024

Just linking for reference as I was linked to Issue #2023 first. We're also seeing this on 11.0.24.

@pklada
Copy link

pklada commented Apr 11, 2024

Does anyone have a workaround for this? It breaks for us too

@ConsoleTVs
Copy link

Does anyone have a workaround for this? It breaks for us too

Fix it to 11.0.10

@Roon311
Copy link

Roon311 commented Apr 11, 2024

@pklada
Reverting to version v10.12.2 worked for me.

@6thpath
Copy link

6thpath commented Apr 12, 2024

@pklada Reverting to version v10.12.2 solved worked for me.

10.12.2 does not work for me, 11.0.10 does

@pklada
Copy link

pklada commented Apr 12, 2024

I'd prefer not to revert if possible as we're relying on some more recent fixes. Would be nice if there was some update on this specific issue as it seems like it is affecting a number of others

@pklada
Copy link

pklada commented Apr 12, 2024

@mattgperry do you have any thoughts or should i just downgrade for now?

@luluxia
Copy link

luluxia commented Apr 18, 2024

I have the same issue.
https://codesandbox.io/p/devbox/great-brattain-hc9kgz
but i found using non-repeating key can solve it.

@kangju2000
Copy link

@VrTech
Copy link

VrTech commented Apr 18, 2024

I have the same issue. https://codesandbox.io/p/devbox/great-brattain-hc9kgz but i found using non-repeating key can solve it.

Good find!
Using count as key can hot fix this for now
const [count, setCount] = useState(0);
or reverting to 11.0.10 works as well.

@Thanaen
Copy link

Thanaen commented Apr 18, 2024

I have the same issue. https://codesandbox.io/p/devbox/great-brattain-hc9kgz but i found using non-repeating key can solve it.

I can reproduce the bug in this codesandbox, just click quickly enough
framer-bug

@luluxia
Copy link

luluxia commented Apr 18, 2024

I have the same issue. https://codesandbox.io/p/devbox/great-brattain-hc9kgz but i found using non-repeating key can solve it.

I can reproduce the bug in this codesandbox, just click quickly enough

change the key attribute in line 21 will fix it. I wrote a comment there.

@Thanaen
Copy link

Thanaen commented Apr 18, 2024

@luluxia Ouuups, I thought the sandbox applied the fix, sorry! 😄

@VrTech
Copy link

VrTech commented Apr 19, 2024

@luluxia However, I found out the solution is not working with staggering children. :(

@RareSecond
Copy link

Am experiencing the exact same issue, but in a different setup. There seem to be cases where exit is never called, and the potential for it not being called seems to be indeed tied to opacity. If I remove the opacity on my exit, it will always get called.

Here's an example. If you slowly hover over the dots on the right, it works as expected. However, once you start going faster, it sometimes bugs and multiple divs remain visible

image

Important part is that, if you remove opacity from the exit animation, it will work perfectly fine

@Thanaen
Copy link

Thanaen commented Apr 19, 2024

@RareSecond
This seems to solve the problem of "deleting" the object, but there's still something wrong with it
With opacity:
framer-presence-issue

Without opacity:
framer-bug-bis

@J4v4Scr1pt
Copy link

J4v4Scr1pt commented Jun 3, 2024

Same Issue:
#2693

I can also confirm that the suggestion above with removing the exit opacity works.

@harrisonhoward
Copy link

harrisonhoward commented Jun 15, 2024

I'm using 11.0.25 and experiencing similar issues with cancelling the exit animation part-way through. This is the recording of it using Loom. Notifiable from the video, it flickers with no component rendered and if you spam it quick enough the project you were looking at disappears, when you go to any other project it will only show the hidden project.

11.0.10 doesn't fix the flickering issue but resolves everything else. I will link the code below.

This is the Projects route component Projects.tsx
This is the card component that holds the ribbons animation (still working on it) ProjectCards.tsx

To get the exit and entrance animations to work I have all projects rendered. For any project not selected it just returns null in the map, couldn't think of another way of doing it.

EDIT:
I think the solution I'm going to go for is this. Debounce the state change so it does the following, the slider updates instantaneously but the selected project will only change to the new value if it's currently not exiting.

@harrisonhoward
Copy link

To follow-up, this code seemed to have to fix it sort of on the latest version. It only flickers if you return back to the same project while it's exiting to the new one.

useDebouncedValue

    const [selectedProject, setSelectedProject] = useDebounceValue(
        () => getProjectByYearAndIndex(activeYear, activeProjectIndex),
        250
    );
    useEffect(() => {
        const newProject = getProjectByYearAndIndex(
            activeYear,
            activeProjectIndex
        );
        if (selectedProject?.id !== newProject?.id) {
            setSelectedProject(newProject);
        }
    }, [activeYear, activeProjectIndex]);

@LeonLiu2020
Copy link

LeonLiu2020 commented Jul 2, 2024

@pklada Reverting to version v10.12.2 solved worked for me.

10.12.2 does not work for me, 11.0.10 does

thanks,11.0.10 works for me.
After two days of repeated debugging, none of the methods mentioned in the other issues worked
Only downgrading the version was effective.
This bug has been around for several years since version 9.x?

Here are two links. The code is the same except for the version of framer-motion.
11.2.12: https://codesandbox.io/p/devbox/framer-motion-11-2-12-s2rwgt
11.0.10:https://codesandbox.io/p/devbox/framer-motion-11-0-10-6f43vg

framer-motion11.2.12.mp4

11.2.12

framer-motion11.0.10.mp4

11.0.10 works

@GunnerCat
Copy link

@pklada Reverting to version v10.12.2 solved worked for me.

10.12.2 does not work for me, 11.0.10 does

thanks,11.0.10 works for me. After two days of repeated debugging, none of the methods mentioned in the other issues worked Only downgrading the version was effective. This bug has been around for several years since version 9.x?

Here are two links. The code is the same except for the version of framer-motion. 11.2.12: https://codesandbox.io/p/devbox/framer-motion-11-2-12-s2rwgt 11.0.10:https://codesandbox.io/p/devbox/framer-motion-11-0-10-6f43vg

framer-motion11.2.12.mp4
11.2.12

framer-motion11.0.10.mp4
11.0.10 works

did the same thing, can approove that it worked 👍

@ConsoleTVs
Copy link

We found out that the opacity sometimes didn't work. We relied a lot in this library and are beginning to strip down bits of it due this bug.

@LeonLiu2020
Copy link

@ConsoleTVs @GunnerCat
After a few days of trying, I resolved all issues using version 11.2.12, including opacity and blur. Could you provide a CodeSandbox link so I can see if I can help?

@justrealmilk
Copy link

@pklada Reverting to version v10.12.2 solved worked for me.

10.12.2 does not work for me, 11.0.10 does

thanks,11.0.10 works for me. After two days of repeated debugging, none of the methods mentioned in the other issues worked Only downgrading the version was effective. This bug has been around for several years since version 9.x?

Here are two links. The code is the same except for the version of framer-motion. 11.2.12: https://codesandbox.io/p/devbox/framer-motion-11-2-12-s2rwgt 11.0.10:https://codesandbox.io/p/devbox/framer-motion-11-0-10-6f43vg

framer-motion11.2.12.mp4
11.2.12

framer-motion11.0.10.mp4
11.0.10 works

@LeonLiu2020

@pklada
Copy link

pklada commented Jul 11, 2024

This is now the most commented on and "liked" issue (even more if you count the duplicates). Would be cool to at least get a comment on if its being looked into.

@GunnerCat
Copy link

@ConsoleTVs @GunnerCat After a few days of trying, I resolved all issues using version 11.2.12, including opacity and blur. Could you provide a CodeSandbox link so I can see if I can help?

sorry for the late respond, This is my code, for some odd reason, this is the same exact code that im using the whole time, the CodeSandBox also uses 11.3.2 framer motion version, and for some UNGODLY REASON IT WORKS.

so at your code, does including opacity and blur fixes the problem?

@WinnieS0728
Copy link

"framer-motion": "^11.2.11",
"macOS":"14.4.1"

I have same issue here, but I solve it in a silly way.

add Math.random() in key

<AnimatePresence initial={false} mode="popLayout" custom={direction}>
    <motion.section
        key={`${id}-${Math.random()}`}
        className="w-full h-100 relative cursor-pointer"
        style={{
            perspective: '1400px',
        }}
        onClick={() => {
            setIsFlipped((prev) => !prev);
        }}
        variants={sectionMotion}
        custom={direction}
        initial="init"
        animate={['enter', 'show']}
        exit={['exit', 'hide']}
        transition={{
            type: 'tween',
            duration: 0.2,
        }}
    >
        <MotionCard text={back} show={!isFlipped} />
        <MotionCard text={front} show={isFlipped} />
    </motion.section>
</AnimatePresence>;

I think is the exit props hold this component from unmount but in react this component mount again, so now framer-motion read two component having same key, somehow break the view.

if there is any better solution ?

@LeonLiu2020
Copy link

sorry for the late respond, This is my code, for some odd reason, this is the same exact code that im using the whole time, the CodeSandBox also uses 11.3.2 framer motion version, and for some UNGODLY REASON IT WORKS.

so at your code, does including opacity and blur fixes the problem?

Sandbox not found.
And in the latest version of framer-motion, I can use opacity and blurs normally, perform well regardless of how quickly the components refresh. I will upload a new example later.

@tnfAngel
Copy link

Any updates here? I have the same problem

@Flamenate
Copy link

Flamenate commented Jul 17, 2024

sorry for the late respond, This is my code, for some odd reason, this is the same exact code that im using the whole time, the CodeSandBox also uses 11.3.2 framer motion version, and for some UNGODLY REASON IT WORKS.
so at your code, does including opacity and blur fixes the problem?

Sandbox not found. And in the latest version of framer-motion, I can use opacity and blurs normally, perform well regardless of how quickly the components refresh. I will upload a new example later.

I'm also using the latest version (11.3.4) but the opacity issue persists. Can you upload the example you're using?

@LeonLiu2020
Copy link

LeonLiu2020 commented Jul 17, 2024

@tnfAngel @Flamenate

AnimatePresence works by detecting when Direct Child are removed from the React tree.

base on framer-motion 11.3.4.
when used in conjunction with radix-primitive, the same usage behaves inconsistently across different Radix-primitives components.
For radix-primitive components that use the asChild prop, sometimes they can be used directly as child nodes, and other times they cannot.

Placing a motion.div as a direct child at the appropriate position can solve the problem for most cases.

Below are examples using radix-accordion, radix-context-menu, and radix-tooltip.
link:
https://codesandbox.io/p/devbox/framer-motion-11-3-4-34sjjk

video:

11.3.4.mp4

These are some methods I have tried, which have solved all the issues I encountered:

  1. Elevate or lower the wrapping scope. Searching on Google for the usage of framer-motion with radix-primitives may reveal incorrect states during fast refresh.
  2. Add a fixed key. Dynamic keys did not help me , even lost the exit animation in a test
  3. Add a motion.div at the outermost layer without adding a key. This is effective and has resolved most of my radix-primitive exit animation issues.

I am not sure about your use case, but if this does not help you, please create a sandbox link.

@Flamenate
Copy link

@tnfAngel @Flamenate

AnimatePresence works by detecting when Direct Child are removed from the React tree.

base on framer-motion 11.3.4. when used in conjunction with radix-primitive, the same usage behaves inconsistently across different Radix-primitives components. For radix-primitive components that use the asChild prop, sometimes they can be used directly as child nodes, and other times they cannot.

Placing a motion.div as a direct child at the appropriate position can solve the problem for most cases.

Below are examples using radix-accordion, radix-context-menu, and radix-tooltip. link: https://codesandbox.io/p/devbox/framer-motion-11-3-4-34sjjk

video:

11.3.4.mp4
These are some methods I have tried, which have solved all the issues I encountered:

  1. Elevate or lower the wrapping scope. Searching on Google for the usage of framer-motion with radix-primitives may reveal incorrect states during fast refresh.
  2. Add a fixed key. Dynamic keys did not help me , even lost the exit animation in a test
  3. Add a motion.div at the outermost layer without adding a key. This is effective and has resolved most of my radix-primitive exit animation issues.

I am not sure about your use case, but if this does not help you, please create a sandbox link.

This was very helpful, thanks!

@Flamenate
Copy link

Flamenate commented Jul 17, 2024

I have the same issue. https://codesandbox.io/p/devbox/great-brattain-hc9kgz but i found using non-repeating key can solve it.

This doesn't work as expected when there are multiple children inside AnimatePresence. When you change only one child, all children are rerendered and reanimated despite having different keys.
Here's an example: https://codesandbox.io/p/devbox/great-brattain-forked-npsfc8

Edit: it made sense for the children to reanimate because I had used the same key variable and added to it (key={key + 10})
It seems like using a different state value like in the example solves this issue, but it's not practical when you have multiple children in a list.

hyp3rflow added a commit to DevKor-github/devkor.club-front that referenced this issue Jul 18, 2024
@mattgperry
Copy link
Collaborator

My suspicion given that this always(?) involves opacity and switching back to a previously existing component, that there's a bug in how WAAPI animations resolve after being interrupted.

So I'm going to write a browser test that encapsulates this behaviour and then figure out a fix.

@web3techlord
Copy link

web3techlord commented Oct 31, 2024

"framer-motion": "^11.11.9"

<AnimatePresence>
              {animations.map((animation) => (
                <motion.div
                  key={animation.id}
                  initial={{ opacity: 1, y: 0 }}
                  animate={{ opacity: 0, y: -400 }}
                  exit={{ opacity: 0 }}
                  transition={{
                    x: { type: "spring", stiffness: 100 },
                    duration: 0.8,
                    delay: 0.01,
                  }}
                  className="select-none font-medium text-[40px] text-amber-500 touch-none"
                  style={{
                    position: "fixed",
                    left: `${animation.x}px`,
                    top: `${animation.y}px`,
                  }}
                >
                  + 1
                </motion.div>
              ))}
            </AnimatePresence>

This animation is used in a tap game. When I tap fast and a lot, game app freezes.
Any idea?

@loxator
Copy link

loxator commented Nov 27, 2024

My use case was Page Transitions and adding the key to the was causing issues. I tried changing it to different things, but it persisted. Weirdly enough, removing it fixed my issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.