motion icon indicating copy to clipboard operation
motion copied to clipboard

[BUG] useTransform does not reflect update of chained MotionValues

Open ali-idrizi opened this issue 2 years ago • 1 comments

I am building a complicated animation, where a transform depends on several motion values. These values are sometimes repeating, so I extracted them to separate motion values, which are calculated using useTransform. I have managed to reproduce the issue with a very simple example:

const a = useMotionValue(0);
const aHalf = useTransform(a, (a) => a / 2);
const aQuarter = useTransform(aHalf, (h) => h / 2);

const result = useTransform([a, aQuarter], ([a, aQuarter]) => {
  // the aQuarter MotionValue is eventually updated to `25`, but it is never reported here. This will log `100, 0` instead of `100, 25`
  console.log({ a, aQuarter });
  return a + aQuarter;
});

useMotionValueEvent(a, "change", (v) => console.log("a", "change", v));
useMotionValueEvent(aQuarter, "change", (v) => console.log("aQuarter", "change", v));
useMotionValueEvent(result, "change", (v) => console.log("result", "change", v));

React.useEffect(() => {
  setTimeout(() => a.set(100), 500);
}, []);

Here is a Codesandbox of the same: https://codesandbox.io/s/framer-motion-enter-animation-forked-4jfkdc?file=/src/App.tsx

If you check the logs you will notice:

a change 100
{a: 100, aQuarter: 0}
result change 100
aQuarter change 25

As you can see, the useTransform for result never logs the aQuarter value of 25, while the same is being reported by useMotionValueEvent. This issue results in the transform outputting an incorrect value for result of 100, while it is supposed to be 125.

ali-idrizi avatar Aug 07 '23 11:08 ali-idrizi

I concur.

I have the following transform:

const { scrollYProgress } = useScroll({
    target: containerRef,
    offset: ["start end", "end end"],
 });
  
const progress = useTransform(scrollYProgress, [0, 0.3, 0.7], [0, 0, 1]);

const vidScale = useTransform(
    progress,
    [0, 1],
    [1, 9],
  );
  
// even though progress will be 1, vidScale won't reach it's target. 
progress.on("change", (v) => { console.log(v, vidScale.get() });

Even though progress reaches 1, headingScale is shy of it's needed target (9 in this example).

piotrnajda3000 avatar Aug 20 '24 10:08 piotrnajda3000