diff --git a/packages/framer-motion/src/value/__tests__/use-transform.test.tsx b/packages/framer-motion/src/value/__tests__/use-transform.test.tsx index 4903df216e..67284c14b1 100644 --- a/packages/framer-motion/src/value/__tests__/use-transform.test.tsx +++ b/packages/framer-motion/src/value/__tests__/use-transform.test.tsx @@ -1,6 +1,6 @@ import { render } from "../../../jest.setup" import * as React from "react" -import { motion } from "../../" +import { frame, motion } from "../../" import { useMotionValue } from "../use-motion-value" import { useTransform } from "../use-transform" import { MotionValue, motionValue } from ".." @@ -56,6 +56,33 @@ describe("as function with multiple values", () => { }) }) +describe("as function with no passed MotionValues", () => { + test("sets initial value", async () => { + const x = motionValue(4) + const Component = () => { + const y = useMotionValue("5px") + const z = useTransform(() => x.get() * parseFloat(y.get())) + return + } + + const { container } = render() + expect(container.firstChild).toHaveStyle( + "transform: translateX(4px) translateY(5px) translateZ(20px)" + ) + + x.set(5) + + await new Promise((resolve) => { + frame.postRender(() => { + expect(container.firstChild).toHaveStyle( + "transform: translateX(5px) translateY(5px) translateZ(25px)" + ) + resolve() + }) + }) + }) +}) + describe("as input/output range", () => { test("sets initial value", async () => { const Component = () => { diff --git a/packages/framer-motion/src/value/index.ts b/packages/framer-motion/src/value/index.ts index 4778ecf47c..3c3f87a288 100644 --- a/packages/framer-motion/src/value/index.ts +++ b/packages/framer-motion/src/value/index.ts @@ -48,6 +48,10 @@ export interface MotionValueOptions { owner?: Owner } +export const collectMotionValues: { current: MotionValue[] | undefined } = { + current: undefined, +} + /** * `MotionValue` is used to track the state and velocity of motion values. * @@ -314,6 +318,10 @@ export class MotionValue { * @public */ get() { + if (collectMotionValues.current) { + collectMotionValues.current.push(this) + } + return this.current } diff --git a/packages/framer-motion/src/value/use-computed.ts b/packages/framer-motion/src/value/use-computed.ts index 5e4938e304..4c22f893ed 100644 --- a/packages/framer-motion/src/value/use-computed.ts +++ b/packages/framer-motion/src/value/use-computed.ts @@ -1,13 +1,21 @@ -import type { MotionValue } from "." +import { collectMotionValues, type MotionValue } from "." import { useCombineMotionValues } from "./use-combine-values" -let collectMotionValues: MotionValue[] | undefined = undefined - export function useComputed(compute: () => O): MotionValue { - collectMotionValues = [] + /** + * Open session of collectMotionValues. Any MotionValue that calls get() + * will be saved into this array. + */ + collectMotionValues.current = [] + compute() - const value = useCombineMotionValues(collectMotionValues, compute) - collectMotionValues = undefined + + const value = useCombineMotionValues(collectMotionValues.current, compute) + + /** + * Synchronously close session of collectMotionValues. + */ + collectMotionValues.current = undefined return value } diff --git a/packages/framer-motion/src/value/use-transform.ts b/packages/framer-motion/src/value/use-transform.ts index b530261168..4f0b43b5dc 100644 --- a/packages/framer-motion/src/value/use-transform.ts +++ b/packages/framer-motion/src/value/use-transform.ts @@ -2,6 +2,7 @@ import { MotionValue } from "../value" import { transform, TransformOptions } from "../utils/transform" import { useCombineMotionValues } from "./use-combine-values" import { useConstant } from "../utils/use-constant" +import { useComputed } from "./use-computed" export type InputRange = number[] type SingleTransformer = (input: I) => O