react-spring
react-spring copied to clipboard
[bug]: Spring reference seem to be shared between instances of the same component when using imperative API
Which react-spring target are you using?
- [x]
@react-spring/web - [ ]
@react-spring/three - [ ]
@react-spring/native - [ ]
@react-spring/konva - [ ]
@react-spring/zdog
What version of react-spring are you using?
10.0.1
What's Wrong?
The spring reference seems to be shared between renders, when using a callback with useSpring() (needed for access to imperative API). This bug is only reproducible after upgrading from 10.0.0 → 10.0.1, and the only possible explanation is due to this one-liner change here: https://github.com/pmndrs/react-spring/compare/v10.0.0...v10.0.1#diff-e1288b0efcce202f0575295aec86c6f33c5d81adac9751131dc5d2b08e40e73a
The only logical change between tehse two versions is that the updates.current ??= [] line was removed, which I suspect have triggered this behavior.
To Reproduce
Use the following contrived example: the <Toggle> component will tween a value randomly assigned to it using react-spring, but when clicking between different toggles, the previously clicked button value will also be mutated as the spring is erroneously run:
https://codesandbox.io/p/sandbox/7cz48k (uses 10.0.1, broken)
import { ComponentPropsWithRef, useEffect } from "react";
import { animated, useSpring, to } from "@react-spring/web";
type Props = Omit<ComponentPropsWithRef<"button">, "value"> & {
value: number;
};
export const Button = ({ value, ...props }: Props) => {
// NOTE: This is a VERY contrived example, as with the simplified code it is easier not to use a callback
const [springs, api] = useSpring(() => ({
ratio: 0,
}));
useEffect(() => {
api.stop().start({
ratio: value,
});
}, [api, value]);
return (
<animated.button type="button" {...props} value={springs.ratio}>
{to([springs.ratio], (r) => r.toFixed(3))}
</animated.button>
);
};
https://github.com/user-attachments/assets/a6bcf261-4f7b-4749-935b-62edcfe19b40
The same code does not have this incorrect behavior when downgrading back to 10.0.0:
https://codesandbox.io/p/sandbox/2vclkz (uses 10.0.0, works)
https://github.com/user-attachments/assets/5a1eafda-de15-44d8-818a-5aeab81468d7
Expected Behaviour
The spring instance should not be shared between difference instances of the same component.
Link to repo
- Working example when using 10.0.0: https://codesandbox.io/p/sandbox/2vclkz
- Broken example when using 10.0.1: https://codesandbox.io/p/sandbox/7cz48k