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

Ensure AnimatePresence executes exiting animations in sequence #2477

Merged
merged 4 commits into from
Jul 24, 2024

Conversation

regexyl
Copy link
Contributor

@regexyl regexyl commented Jan 5, 2024

This PR fixes #2462.

It also fixes 3 tests (i.e. "Only renders one child at a time if mode === 'wait'", "Fast animations with wait render the child content correctly", "Fast animations with wait render the child content correctly (strict mode disabled)") where not enough leeway is given for exiting elements to completely exit from the DOM.

Before

framer-motion-bug.mov

Now

Screen.Recording.2024-01-06.at.00.54.36.mov


const exitingChildren = useRef(
new Map<ComponentKey, ReactElement<any> | undefined>()
).current

// Keep a living record of the children we're actually rendering so we
// can diff to figure out which are entering and exiting
const presentChildren = useRef(childrenToRender)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed presentChildren for clarity - filteredChildren, exitingChildren and allChildren are enough to maintain the status quo

@regexyl regexyl marked this pull request as draft January 5, 2024 17:09
@regexyl regexyl marked this pull request as ready for review January 5, 2024 17:34
@regexyl
Copy link
Contributor Author

regexyl commented Jan 5, 2024

@mattgperry I'm not sure why the test under framer-motion-3d is failing - do you have a clue?
edit: it's passed, maybe flaky? 👀

@JaeSeoKim
Copy link
Contributor

JaeSeoKim commented Jan 8, 2024

In the past, I've written PR to fix errors in this regard. I'm linking because I think it would be good to refer to!

@regexyl
Copy link
Contributor Author

regexyl commented Jan 8, 2024

Thanks @JaeSeoKim! Just had a quick look-through, and it seems like there are two main problems the PR was trying to solve - (1) bringing useRef to exitingChildren (also later separately solved through #2113), and (2) the algorithm that decides how exiting, current and entering elements mesh together.

This PR tries to solve a different problem where a quick waterfall of existing elements do not exit in sequence (i.e. elements exit in quick succession, but in different times), instead of how the exiting/current/entering elements should be rendered - though it seems like a pretty interesting problem to solve 🦄

@mattgperry
Copy link
Collaborator

Thanks for the excellent PR and apologises it's taken a while to get to. I'll merge and publish today.

@mattgperry mattgperry merged commit f83739f into motiondivision:main Jul 24, 2024
1 check passed
mattgperry added a commit that referenced this pull request Jul 24, 2024
mattgperry added a commit that referenced this pull request Jul 24, 2024
@mattgperry
Copy link
Collaborator

mattgperry commented Jul 24, 2024

Ah apologises. I had to revert this PR because of these lines:

    const filteredChildren = useRef(onlyElements(children))
    filteredChildren.current = onlyElements(children)

The intention here is to update filteredChildren every render. But filteredChildren is essentially a mutable here and React renders are theoretically pure.

Therefore, it's only safe to assign a ref during render on the initial render:

    const filteredChildren = useRef(null)
    if (!filteredChildren.current)
      filteredChildren.current = onlyElements(children)

(Which obviously isn't the intent of this line)

Otherwise what we have is a situation where React could prospectively render something with a children list that isn't ever committed, and an Effect or onExit being run on a filteredChildren list that isn't the one we think it is.

@mattgperry
Copy link
Collaborator

Another issue - or maybe it's been fixed in the meantime? - is I ported the tests in this PR to main 8ee3628 and they pass already so I don't know if they capture the behaviour in the linked issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[BUG] AnimatePresence does not execute exiting animations in sequence during fast renders
3 participants