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 wanted 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
When animating things, we need to use an animated component created via createAnimatedComponent. This higher order function receives a component and wraps it into animation-aware updating logic. In order to update Component's animation, createAnimatedComponent uses useAnimatedProps hook which returns animated props. Those props are later merged into Component styles.
To update the styles, the useAnimatedProps forces change of internal dummy React's state by calling scheduleUpdate. This is the place where the commits are coming from.
By looking at the implementation of other popular animation libraries, we can see they are purposely trying to avoid such behaviours.
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 none commits related to opacity animation:
Similar thing happens in react-spring. Example is taken from web version of the library, but the notion stays 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 even blockers that I am not aware of - that's why I would really appreciate your feedback and insight, thanks a lot! ❤️
The text was updated successfully, but these errors were encountered:
Is there an existing request?
Describe the feature request
Hi folks! 👋
Intro
In this issue, I wanted 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
When animating things, we need to use an
animated
component created viacreateAnimatedComponent
. This higher order function receives a component and wraps it into animation-aware updating logic. In order to updateComponent
's animation,createAnimatedComponent
usesuseAnimatedProps
hook which returns animated props. Those props are later merged intoComponent
styles.react-native-web/packages/react-native-web/src/vendor/react-native/Animated/createAnimatedComponent.js
Lines 37 to 60 in 24212aa
To update the styles, the
useAnimatedProps
forces change of internal dummy React's state by callingscheduleUpdate
. This is the place where the commits are coming from.react-native-web/packages/react-native-web/src/vendor/react-native/Animated/useAnimatedProps.js
Lines 34 to 101 in 24212aa
Potential solution
By looking at the implementation of other popular animation libraries, we can see they are purposely trying to avoid such behaviours.
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 none 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 stays 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 even blockers that I am not aware of - that's why I would really appreciate your feedback and insight, thanks a lot! ❤️
The text was updated successfully, but these errors were encountered: