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

Use ref for exiting children (Fixes #1914) #2113

Merged
merged 3 commits into from May 10, 2023
Merged

Conversation

hluisson
Copy link
Contributor

@hluisson hluisson commented May 8, 2023

Fixes #1914

The onExit callback for exiting children could have stale values for the set of exiting keys. This would lead to the last "exiting" element to not realize they were the last exiting element, and therefore not trigger a force render (specific code below)

if (!exiting.size) {
                presentChildren.current = filteredChildren

                if (isMounted.current === false) return

                forceRender()
                onExitComplete && onExitComplete()
}

This means already-exited elements would still be visible until the next render (if there was one)

I looked into adding a test for this case. However, in tests, the use of React.StrictMode created a lot of extra renders which would "fix" this broken state before I could assert against it. Even experimenting with not using React.StrictMode, I still saw more than 1 render when calling rerender and could not get a clean failing test. Let me know if you have any suggestions!

@mattgperry
Copy link
Collaborator

Hey, great PR, thanks! Could you commit the test with multiple renders and no StrictMode so I can look into why it's rerendering?

@hluisson
Copy link
Contributor Author

hluisson commented May 9, 2023

sure - i've pushed the test up! (this test does not fail on main, so it's not reproducing the bug)

Looking at it a bit more, I actually think React Strict Mode is unrelated to the difference in rendering - both the sandboxed app and the tests run in strict mode, with different results.

I adding some console.log statements locally to try to demonstrate with screenshots - one at the top of the "AnimatePresence" component and one in the onExit callback

In my local version of the sandboxed example from the linked issue, I click "toggle" twice in quick succession, and I see the final onExit cb is the last thing executed (this shows the bug: we fail the check !exiting.size that should be calling forceRender() and there isn't a render after the final onExit cb)

Screenshot 2023-05-08 at 9 18 25 PM

when i run the unit test i've just committed (adding console.log("toggle clicked!") above the lines where i call rerender) against main, I see the following:
Screenshot 2023-05-08 at 9 40 56 PM

in the test code specifically, both cbs execute in the same tick so there is a final render that corrects the state (so - the test does not fail when it should)

let me know if that makes sense!

@mattgperry
Copy link
Collaborator

Ah yeah that makes sense thanks, I'll take a look!

@mattgperry
Copy link
Collaborator

mattgperry commented May 9, 2023

I think I've got it breaking correctly by changing the test to:

        // Remove the second-to-last element from the array
        await act(async () => {
            rerender(<Component visibleKeys={[0]} />)

            await new Promise<void>((resolve) => {
                //  Resolve after all animation is expected to have completed
                setTimeout(() => {
                    resolve()
                }, 1000)
            })
        })

I think the difference between this and the sandbox is in how act flushes effects.

Edit: Ah but this isn't fixed on branch. I'll keep looking.

@mattgperry
Copy link
Collaborator

Ok I've got a test that fails on main and passes on this branch.

#2119

Once I've merged that I'll merge this and remove the Jest test. Thanks again!

@mattgperry mattgperry merged commit 46fbfd9 into framer:main May 10, 2023
1 check was pending
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] Animate Presence Items Persist if Removed During Another Item's Active Exit Animation
2 participants