pmndrs / react-spring

✌️ A spring physics based React animation library
http://www.react-spring.dev/
MIT License
27.93k stars 1.19k forks source link

[bug]: Spring Config function not called when using Imperative API #2186

Open dragonman225 opened 1 year ago

dragonman225 commented 1 year ago

Which react-spring target are you using?

What version of react-spring are you using?

9.7.3

What's Wrong?

I'd like to use the Imperative API (https://react-spring.dev/docs/concepts/imperative-api) with a Spring Config function (https://react-spring.dev/docs/advanced/config#config-per-springvalue) to customize friction, tension, etc per SpringValue, like this:

const springConfig = (key) => {
  if (key === "opacity")
    return { tension: 60, friction: 10, precision: 0.0001 };
  else if (key === "scaleX") return { tension: 58, friction: 4.3 };
  else if (key === "scaleY") return { tension: 70, friction: 4 };
  return {};
};

const animation = useSpringRef();
const springs = useSpring({
  ref: animation,
  from: { opacity: 0, scaleX: 0.96, scaleY: 0.96 },
  config: springConfig
});

but the config function is never called (example: https://codesandbox.io/s/react-spring-bug-277lrl?file=/App.js).

To Reproduce

With this minimal snippet:

const springConfig = (key) => {
  if (key === "opacity")
    return { tension: 60, friction: 10, precision: 0.0001 };
  else if (key === "scaleX") return { tension: 58, friction: 4.3 };
  else if (key === "scaleY") return { tension: 70, friction: 4 };
  return {};
};

const animation = useSpringRef();
const springs = useSpring({
  ref: animation,
  from: { opacity: 0, scaleX: 0.96, scaleY: 0.96 },
  config: springConfig
});

Or see this codesandbox: https://codesandbox.io/s/react-spring-bug-277lrl?file=/App.js

Expected Behaviour

Spring Config function should be called when using the Imperative API.

Link to repo

https://codesandbox.io/s/react-spring-bug-277lrl?file=/App.js

dragonman225 commented 1 year ago

I revisited the issue and found a way to make the config work—the config must be set via a SpringRef's .start(), like this

animation.start({
  to: { opacity: 1, scaleX: 1, scaleY: 1 },
  config: springConfig
});

By the way, setting the config via a SpringRef's .set() also doesn't work.

animation.set({ config: springConfig }); // not working

Furthermore, looking more into the comparison of Imperative API v.s. stateful component example, I noticed that the StateComponent re-renders because it uses React's state to trigger animation, not because the use of useSpring.

Going back to my code, inspecting it, I realized that if I used useSpring like this:

const [springs, animation] = useSpring(() => ({
  from: { opacity: 0.2, scaleX: 0.2, scaleY: 0.2 },
  config: springConfig
}));

and called animation.start() to trigger animations, the component did not re-render at all. It seemed that I could use the Imperative API without useSpringRef(), and the documentation confused me.

Docker-J commented 9 months ago

Same here. I am really confused that .set() does not work on SpringRef. I have no idea if it is designed to be in this way but seems it shouldn't be according to the documentation.