From 46390cf5e79d3bd2d3be93065cbd8643da2254cc Mon Sep 17 00:00:00 2001 From: Matt Perry Date: Thu, 20 Feb 2025 12:52:40 +0100 Subject: [PATCH] Fixing `AnimatePresence` with `layout` children (#3076) * Fixing AnimatePresence * Updating changelog --- Makefile | 2 +- .../src/tests/animate-presence-layout.tsx | 57 ++++++++----------- .../integration/animate-presence-layout.ts | 14 +++++ .../AnimatePresence/use-presence.ts | 4 +- 4 files changed, 42 insertions(+), 35 deletions(-) create mode 100644 packages/framer-motion/cypress/integration/animate-presence-layout.ts diff --git a/Makefile b/Makefile index 7c9d9b9e85..c860733501 100644 --- a/Makefile +++ b/Makefile @@ -95,7 +95,7 @@ test-e2e: test-nextjs test-html test-react test-react-19 yarn test-playwright test-single: build test-mkdir - yarn start-server-and-test "yarn dev-server" http://localhost:9990 "cd packages/framer-motion && cypress run --headless --spec cypress/integration/drag.ts" + yarn start-server-and-test "yarn dev-server" http://localhost:9990 "cd packages/framer-motion && cypress run --headless --spec cypress/integration/animate-presence-layout.ts" lint: bootstrap diff --git a/dev/react/src/tests/animate-presence-layout.tsx b/dev/react/src/tests/animate-presence-layout.tsx index 6cffaef193..c01a4f7389 100644 --- a/dev/react/src/tests/animate-presence-layout.tsx +++ b/dev/react/src/tests/animate-presence-layout.tsx @@ -1,44 +1,35 @@ import { AnimatePresence, motion } from "framer-motion" -import { useEffect, useState } from "react" +import { useState } from "react" -export const App = () => { - const [width, setWidth] = useState(100) - const [presenceState, setPresenceState] = useState(true) - - useEffect(() => { - if (width === 200) return - const timeout = setTimeout(() => { - setWidth(50) +function Component() { + const [showChild, setShowChild] = useState(true) - setTimeout(() => { - setWidth(200) - }, 1000) - }, 1000) - - return () => clearTimeout(timeout) - }, [width]) + return ( + + + {showChild && Hello} + + ) +} - useEffect(() => { - setTimeout(() => { - setPresenceState(false) - }, 2100) - }, [presenceState]) +export const App = () => { + const [showChild, setShowChild] = useState(true) return ( <> + - {presenceState && ( - - - Presence - + {showChild && ( + + )} diff --git a/packages/framer-motion/cypress/integration/animate-presence-layout.ts b/packages/framer-motion/cypress/integration/animate-presence-layout.ts new file mode 100644 index 0000000000..fed8d5bebf --- /dev/null +++ b/packages/framer-motion/cypress/integration/animate-presence-layout.ts @@ -0,0 +1,14 @@ +describe("AnimatePresence", () => { + it("Ensures all elements are removed", () => { + cy.visit("?test=animate-presence-layout") + .wait(50) + .get("#inner") + .trigger("click", 1, 1, { force: true }) + .wait(100) + .get("#outer") + .trigger("click", 1, 1, { force: true }) + .wait(700) + .get("#box") + .should("not.exist") + }) +}) diff --git a/packages/framer-motion/src/components/AnimatePresence/use-presence.ts b/packages/framer-motion/src/components/AnimatePresence/use-presence.ts index 652f58e2dd..683321bf2f 100644 --- a/packages/framer-motion/src/components/AnimatePresence/use-presence.ts +++ b/packages/framer-motion/src/components/AnimatePresence/use-presence.ts @@ -49,7 +49,9 @@ export function usePresence( const id = useId() useEffect(() => { - if (subscribe) register(id) + if (subscribe) { + return register(id) + } }, [subscribe]) const safeToRemove = useCallback(