You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In this issue, I want to discuss with you how Animated module handles animations on web and potential improvement of it.
Problem
When I was debugging one of the react-navigation navigators animations, it turned out that during screen transitions there are many React's commits triggered that looks like purely related to the animation itself - the number of commits grew in relation to display refresh rate and length of animation.
Here are the results of animating the opacity of a View in a simple demo:
Source code of above example
import{useRef}from"react";import{Animated}from"react-native";import{Button,baseStyle}from"./utils";exportdefaultfunctionAnimatedExample(){constopacity=useRef(newAnimated.Value(1)).current;consthandlePress=()=>{Animated.timing(opacity,{// Just for simplicitytoValue: opacity.__getValue()===1 ? 0.2 : 1,duration: 1000,useNativeDriver: false,}).start();};constanimatedStyle={
opacity,};return(<><Animated.Viewstyle={[baseStyle,animatedStyle]}/><Buttontitle={"Animate me, Animated!"}onPress={handlePress}/></>);}
Question is, how would that impact things in real world app scenario, where there might be some heavy, not properly memoized components?
Analysis
createAnimatedComponent
When animating things, we need to use an animated component created via createAnimatedComponent. It is a higher order function which receives a component and wraps it into animation-aware updating logic. In order to update Component's animation, createAnimatedComponent uses props returned by useAnimatedProps hook. Those props are merged into Component styles after every animation tick.
useAnimatedProps
To update the styles, the useAnimatedProps forces change of internal dummy React's state by calling scheduleUpdate. This is the place where the bulk of commits is coming from.
Potential solution
By looking at the implementation of other popular animation libraries, we can see they are purposely trying to avoid such behaviour, making updates "outside of react".
Reanimated
For example, here are the results of simple demo mentioned above for react-native-reanimated. The two visible commits are ones coming from TouchableOpacity, so there is effectively no commits related to opacity animation:
Similar thing happens in react-spring. Example is taken from web version of the library, but the notion is the same. Here is a recording that shows no actual commits as we are using native button as well:
As a POC the pattern that react-spring uses to update the styles during animation was followed. Instead of updating them by forcing the React's state, a callback was passed from createAnimatedComponent to useAnimatedProps. The callback is responsible to directly change the styles of an animated element.
This approach resulted in 0 commits taking place while animating:
It is very provisional implementation, which goal is to convey the idea. There are definitely reasons to be sceptic about described approach or blockers that I am not aware of.
With that in mind, I am looking forward for your feedback and insight, thanks a lot! ❤️
The text was updated successfully, but these errors were encountered:
Intro
Hi folks! 👋
In this issue, I want to discuss with you how
Animated
module handles animations on web and potential improvement of it.Problem
When I was debugging one of the
react-navigation
navigators animations, it turned out that during screen transitions there are many React's commits triggered that looks like purely related to the animation itself - the number of commits grew in relation to display refresh rate and length of animation.Here are the results of animating the opacity of a View in a simple demo:
Source code of above example
Question is, how would that impact things in real world app scenario, where there might be some heavy, not properly memoized components?
Analysis
createAnimatedComponent
When animating things, we need to use an animated component created via
createAnimatedComponent
. It is a higher order function which receives a component and wraps it into animation-aware updating logic. In order to updateComponent
's animation,createAnimatedComponent
uses props returned byuseAnimatedProps
hook. Those props are merged intoComponent
styles after every animation tick.useAnimatedProps
To update the styles, the
useAnimatedProps
forces change of internal dummy React's state by callingscheduleUpdate
. This is the place where the bulk of commits is coming from.Potential solution
By looking at the implementation of other popular animation libraries, we can see they are purposely trying to avoid such behaviour, making updates "outside of react".
Reanimated
For example, here are the results of simple demo mentioned above for
react-native-reanimated
. The two visible commits are ones coming fromTouchableOpacity
, so there is effectively no commits related to opacity animation:Source code of above example
React Spring
Similar thing happens in
react-spring
. Example is taken from web version of the library, but the notion is the same. Here is a recording that shows no actual commits as we are using native button as well:spring.mp4
Source code of above example
POC
As a POC the pattern that
react-spring
uses to update the styles during animation was followed. Instead of updating them by forcing the React's state, a callback was passed fromcreateAnimatedComponent
touseAnimatedProps
. The callback is responsible to directly change the styles of an animated element.This approach resulted in 0 commits taking place while animating:
createAnimatedComponent modifications
useAnimatedProps modifications
Outro
It is very provisional implementation, which goal is to convey the idea. There are definitely reasons to be sceptic about described approach or blockers that I am not aware of.
With that in mind, I am looking forward for your feedback and insight, thanks a lot! ❤️
The text was updated successfully, but these errors were encountered: