-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RFC / useTransition 🤯 and possible improvements #665
Comments
One thing that would be amazing (and maybe you can already do this, but i just don't know how) is to be able to imperatively update and access the spring that results from the transition. I've been finding it difficult to combine transitions with gesture based controls, so I usually just end up using Maybe something like this (pseudo code)? return transition((visible, style, set) => {
const someGestureFn = (x) => set({ x })
return visible && <a.div style={style}>hello</a.div>
}) |
@bmcmahen indeed, useTransition is the only hook that doesn't support set. We could extend the signature as we have done with the other hooks: const transitions = useTransition(items, config)
const [transitions, update] = useTransition(items, () => config) Another idea would be to normalize the api and remove the two signatures in favour of an optional dependencies array, like useMemo/useEffect/useCallback: const [props, set] = useSpring({ opacity: show ? 1 : 0 }, [show])
const [springs, set] = useSprings(items, item => ({ opacity: show ? 1 : 0 }), [show])
const [springs, set] = useTrail(items, { opacity: show ? 1 : 0 }, [show])
const [transition, set] = useTransition(items, { from: { x: 0 }, enter: { x: 1 } }, []) I would like this very much. Would reduce the api surface and would help us to figure out changes. |
👍 on the new The proposed "function abstraction" (the third example in the OP) is kinda like renderprops for hooks. I like how it abstracts away the responsibility of passing a key, but maybe it's too much magic for some people? I say go for it. I think making the
This is already added to Except currently, it doesn't cause a setter to be returned, which I'm a fan of. I prefer the function syntax for "setter mode". |
Hi Paul! Thanks for creating this awesome animation library. I've been trying to wrap my head around react-spring for a couple of days now, so here are a few observations from a newbies perspective, hope that helps. First of all, I was somewhat confused about the different function signatures with set. Why would you need that in the first place? Can't you just always return an array // either
const [props] = useSpring({opacity: show ? 1 : 0})
// or
const [props, set] = useSpring({opacity: 0})
set({opacity: 1}) This feels much more natural to me, kinda looks like the Second, the useTransition-API was really confusing and unintuitive for me as a beginner as well. I had a simple use case (fading out a single component on unmount) that I wanted to implement, but which felt very awkward with the current API. I kept asking myself things like "why does it return an array? I just want to animate a single component..." or "what is this whole key thing about?". I think your function abstraction suggestion would definitely be a move in the right direction. That being said, I really enjoyed the solution for animating transitions that react-pose went for, which is extremely simple and elegant. I wonder if something like that would be possible with react-spring, too. It might look something like this (just spit-balling, not sure if that could even work with the way react-spring is built): import { animated, useTransition, Transition } from "react-spring";
const [props, set] = useTransition({
from: {}, enter: {}, leave: {},
});
return (
<Transition>
{visible && <animated.div style={props}>hello</animated.div>}
</Transition>
);
Additionally, if you have a list of elements, you could have a const [transitions, set] = useTransitions(items, items => items.key, {
from: {}, enter: {}, leave: {},
});
return (
<Transition>
{transitions.map(({ item, key, props }) => (
<animated.div key={key} style={props}>
{item.text}
</animated.div>
))}
</Transition>
); I feel like splitting useTransition into two things similar to |
I like the idea of splitting useTransition into two things. Maybe useListTransition and useTransition. The latter for single component mounts and unmounts. As a newbie, using arrays and keys when trying to animate a single component on mount / unmount (ie a modal) was a bit confusing 😄 |
const [props, set] = useSpring({ opacity: 0 }) would set opacity to 0 on every render pass. if the parent decides, for whatever reason to render, opacity will go zero. but this can be fixed using dependencies: const [props, set] = useSpring({ opacity: visible ? 1 : 0 }, [visible]) And i agree, this should be the only documented api signature. As for transition and pose's approach. I don't like it. I need things to be explicit without going into too much overhead. But that wrapper is magic again, and it will use React.cloneChildren and mutate stuff. React-spring is shooting for something that gives you control. In this case it costs 1 or 2 lines more, but i think sometimes it's worth it. @aleclarson the problem is that two api signatures cause unneeded complexity. We should use one signature and perhaps allow users to still use functions, but only to avoid object recreating, like useState. const [props, set] = useSpring(() => ({ opacity: visible ? 1 : 0 }), [visible]) That would remove half of the needed documentation and beginners aren't confronted with two signatures any longer. They just use this one, if they need set or not. |
Isn't internally generating the keys an option, perhaps using a WeakMap, so the short signature can be used for everything? |
@mfarhadpur which signature? |
@drcmda He's talking about omitting the @mfarhadpur Yeah, that sounds like a great idea! It doesn't even need to be a WeakMap, just a Map will do. |
@drcmda Yes, I mean the proposed |
That could work! |
@drcmda So, it's coming ?:) |
still in consideration. the only worry i have is having yet another major for this. it would simplify the api, since you only need one signature. but people would have to adjust their code once again. there's a pr now that had this working, it looked good to me at least. |
@drcmda Checking the arguments passed would enable supporting both "legacy" and new API, no? |
I don't currently need this, but it's nice to have for sure. Anyone that wants to implement what @phaistonian said is welcome to. @drcmda has already done most of the work. Just follow these commands:
|
Hmm, sure about that? For instance ... const props = useSpring({ x: 1 }) would now universally be: const [props /*, set*/] = useSpring({ x: 1 }) The call signature is the same but the result is different. Not a big deal, but would force people to once again fix their code by wrapping props into brackets. I like the api for sure, and these 2 signatures have brought about unwanted confusion, it's been one of the main criticisms for sure - so i'm all for it. But then again, ... is it good to break it once again after v8? 🤔 |
For v9, we could require the deps array to opt-in to the // Still works like v8
const props = useSpring({ x: 1 })
// These are equivalent in v9 (but the latter is deprecated)
const [props, set] = useSpring({ x: 1 }, [])
const [props, set] = useSpring(() => ({ x: 1 })) |
interesting ... you two saved the day! 😍 |
Indeed that could work - sorry for being late to this part :) ps: The API is half of the project; it defines scalability, attraction, and endurance. Not once have I regretted introducing breaking changes in favor of extra "sanity". |
The new API for |
Now available in v9.0.0-rc.2 #985 |
As we all know, transitions are hard. 🤯
If you want put your ideas in here and we'll discuss them, no matter how wild they are.
What people don't easily understand is that transition is a value retainer, it's not magic, it just saves a value (or an array of values) and looks for the addition or removal of keys. On changes it can retain the old value and pass it to the view, so that it can fade out an old state. So that has to be expressed better in the docs for sure. But the api is a little weird, too.
A transition result is always an array. In theory this probably cannot change since there are reasons for it, it has to be documented better. Maybe it can be abstracted, though.
That array contains objects made of
{ item, key props }
, which is weird. Often people see "item" down in the view section and don't know where it comes from. This can be changed.Some ideas:
The current solution:
The text was updated successfully, but these errors were encountered: