pmndrs / react-spring

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

react-native useNativeDriver #299

Open madebytilde opened 6 years ago

madebytilde commented 6 years ago

Are you planning to support useNativeDriver for react-native? Which perform the animation on the UI thread without having to go through the bridge on every frame.

drcmda commented 6 years ago

It would be nice. If this comes in as a contribution/PR i'm happy to support/review/merge. On my own i think that's unlikely due to time constraints.

From looking at the source https://github.com/facebook/react-native/tree/master/Libraries/Animated/src it basically sidesteps animation and just forwards the animation config. Just raises the question how much the two ends are wired together.

mmazzarolo commented 5 years ago

@drcmda totally new to react-spring, great project (and docs!). Jumping here just to say that useNativeDriver can only be applied to a specific subset of fields (e.g.: you can use it on translations/scale/rotations but you can't use it on margins/paddings/width).

drcmda commented 5 years ago

@mmazzarolo that's true unfortunately, but even for a subset it could be very valuable, i would love to support it!

mmazzarolo commented 5 years ago

@drcmda sure! I just wanted to point that out because it might be useful for implementing useNativeDriver πŸ‘
I just discovered react-spring this morning and I don't have enough knowledge to contribute directly but it looks like it doesn't use RN Animated API under the hood (e.g.: timing/spring)... which is where you should declare the useNativeDriver flag.

drcmda commented 5 years ago

It's a fork from react-native's animated, we're now quite far from it, trying to remove complexity, but the principles still hold. Someone who knows RN's nativeDrive could probably implement it rather quickly.

JasCodes commented 5 years ago

@drcmda Love the project, going to try with react native, how much u think thr might be performance boost if implemented?

thg303 commented 5 years ago

I tried the Animated api itself without "useNativeDriver" it's dead slow and jumpy on the emulators (even on GenyMotion).

drcmda commented 5 years ago

The emulator isn't going to give great results but using animated without nativedriver on mobile is otherwise fine, depending on the animation of course. We should even be a bit faster than standard RN animated, since this fork does a lot of optimisation like sharing one RAF loop instead of many for each AnimatedValue, things like that. nativeDriver, like @mmazzarolo said, is limited to a couple of props, everything else won't work with it anyway. But if anyone of you wants to give it a shot trying to get nativeDriver in, i'd support you with everything i can.

mmazzarolo commented 5 years ago

It's a fork from react-native's animated, we're now quite far from it, trying to remove complexity, but the principles still hold.

Is the RN Animated API used anywhere in the code? I just checked and I wasn't able to find it.
Or maybe you mean you re-wrote it from ground up? I'll play a bit with it.

but using animated without nativedriver on mobile is otherwise fine, depending on the animation of course

πŸ€” Hm, from my experience useNativeDriver is almost essential when animating using the Animated API, otherwise you'll experience lag and delays each time you do a blocking action in the JS thread (sadly, even if you optimize the JS code you won't be able to achieve the native performance).

is limited to a couple of props, everything else won't work with it anyway.

Actually I think these props cover the 90% of the use cases (especially translations + scale + opacity) 😁 But yeah, adding support to a few more props would be awesome because right now you're often forced to tune the interpolators a lot even for simple animations.

drcmda commented 5 years ago

yes, under /src/animated. the barebones are all there, though it's a lot less complex now. things like animatedXY don't exist because animatedArray can animate arrays of any length, spring/timing don't exist because configs can accept spring props or duration, and the class that holds it all together is Controller, whose "raf" updater nativeDriver would then skip. I think all we need to do here is communicate our intent to the driver that a new animation is supposed to start. This would happen inside Controller.js in start/stop, and it's gonna need the end-state callback.

Previously animated would kind of delegate animation across multiple objects: AnimatedValue and so on. This is all gone. The only class that ever animates is Controller. The rest are just needed to store locals, callbacks and so on - but they don't carry any animation logic any longer.

This region is probably going to be affected: https://github.com/drcmda/react-spring/blob/master/src/animated/Controller.js#L245-L282

slorber commented 5 years ago

hey, just want to notify I released a hooks based lib for RN Animated that permit to use the native driver: https://github.com/slorber/react-native-animation-hook

I don't know exactly how this lib works internally, but if RN should be supported we should rather reuse existing native primitives (native driver, native spring formulas...) rather than having a js implementation of them.

As far as I understand, this lib is more suited for DOM usage right?

drcmda commented 5 years ago

It's cross-platform by nature, including react-native. I don't think supporting nativeDriver would be hard to do, we are basically using a cooked down Animated underneath. All nativeDriver does is forward configs and end-state callbacks to the native layer. But without contribution there's no time left for me to look into that atm.

Elindorath commented 5 years ago

Hi everyone,

I've been going through both react-spring and Animated API a little bit and I don't really understand how you would do that.

I have clearly seen the correspondences between the two but as I understand it, using useNativeDriver replaces the requestAnimationFrame call with the execution of an internal function (__startNativeAnimation) that interacts directly with the NativeAnimatedModule. This module is the only API exposed. The only way I can think of right now would be to let the react-spring user define a function to use instead of requestAnimationFrame. This would allow the use of the NativeAnimatedModule.startAnimatingNode function but unfortunately it needs some internal ids.

I would happily work on a PR if I could see a proper way to do it but I need some help to figure it out.

Edit: For anyone interested, I leave here the path taken by Animated.timing with useNativeDriver set to true:

Libraries/Animated/src/AnimatedImplementation.js
Libraries/Animated/src/nodes/AnimatedValue.js
Libraries/Animated/src/animations/TimingAnimation.js
Libraries/Animated/src/animations/Animation.js
Libraries/Animated/src/NativeAnimatedHelper.js
drcmda commented 5 years ago

Actually, requestanimationframe is exchangeable, see src/animated/Globals.js

But not sure if that's the right spot. The main class that holds everything together is animated/Controller.js. In there you'll find the start and stop functions. I think Globals.js would need some new injection path which you'll drop in src/targets/native/index.js, Controller would read that out and determine if it goes through its own logic (start/stop -> requestAnimationFrame) or NativeAnimatedModule.startAnimatingNode.

IssueHuntBot commented 5 years ago

@issuehuntfest has funded $80.00 to this issue. See it on IssueHunt

JasCodes commented 5 years ago

@drcmda Are you aware of react-native's turbo modules?

brunolemos commented 5 years ago

I'd love if some contributor could work on this, having some serious performance issues on android (#570).

I've just tweeted about it: https://twitter.com/brunolemos/status/1121864324803375106?s=21

aleclarson commented 5 years ago

@brunolemos I'm planning to sometime soon. Probably won't make v9 but we'll see

brunolemos commented 5 years ago

@kmagiera since you have a lot of experience with react-native Animated, could you tell us some of your thoughts on what would be the best approach here?

react-spring has a custom implementation of Animated. We plan supporting useNativeDriver, no idea if it's possible. @aleclarson seems to know.

What if we could make react-spring use Reanimated on native? Do you think that would have more benefits?

https://github.com/kmagiera/react-native-reanimated

kmagiera commented 5 years ago

Not really familiar with react-spring and it’s implemetation for react-native but this appears to be sth reanimated should help with.

The goal of reanimated was to provide performant backend for building higher level abstractions like this one. It is very powerful and supports all type of native view params (unlike Animated nativeDriver which only has a limited subset of properties).

aleclarson commented 5 years ago

I've done some planning around a native frameloop. I'll share details when it gets fleshed out more. πŸ‘

brunolemos commented 5 years ago

It is very powerful and supports all type of native view params (unlike Animated nativeDriver which only has a limited subset of properties)

This is one of the nice things about Reanimated, it's not limited to just some properties like the official Animated and was also made with 60fps animations in mind, running in native and not on js thread afaik.

I've done some planning

@aleclarson maybe share with us? so we can discuss. I wonder if we wouldn't be better just using Reanimated or take inspirations from there. Maybe we shouldn't built something totally new since it's already battle-tested super performant.

It could be an optional dependency. It comes built-in with expo and shouldn't be hard to install on non-expo. Or we could have a way to integrate it on user land (maybe there is already? cc @drcmda).

aleclarson commented 5 years ago

The native frameloop receives JS animation configs and executes them on their native AnimatedValue nodes. We can borrow (or at least take inspiration from) a lot of the native logic for conditional interpolation from Reanimated, but I want to experiment with the JavaScript API.

Somewhat related: We should consider getting react-use-gesture to use react-native-gesture-handler at some point, too.

sridharAJ commented 5 years ago

Hi @aleclarson thanks for this wonderful library. I have just started exploring react-spring for react-native animation use cases. So for my use case I am using opacity and scale property, without useNativeDriver flag its not smooth at all in Android. It's working ok in IOS.

So without useNativeDriver flag I can't go prod for sure.

Could you please update the status in terms of approach and plan. Which will be very helpful for me to take a decision clearly.

aleclarson commented 5 years ago

@sridharAJ Have you tested it with "production React" and with the debugger disabled? I'm developing for macOS at the moment, where JS-driven animation works well enough. I'll be doing mobile dev by the end of this year, so that's when I'll be looking into native-driven animations (if necessary).

sridharAJ commented 5 years ago

@aleclarson Yes I have tested in "production react" build only. I am animating list item image on FlatList when it's coming to view port. So already JS thread is heavy with that. Thats why I need native driver. Anyway for now I fall back with react-native animation which support native driver. Thank you for your quick reply :)

gtbono commented 2 years ago

With React Native Fabric being enabled in 0.68, will this still be necessary?

joshuaellis commented 2 years ago

Would you be able to remind me why fabric will be so good? ☺️

gtbono commented 2 years ago

I'm not a specialist, but AFAIK it is about bridgeless access from React to Native and vice versa