Reducing Costly Renders During Gesture Animations in React Native
Building highly performant animations in React Native can be tricky, particularly when dealing with gestures. Gesture animations are tricky due to the frequency the events from the gesture handler are fired, sometimes only 30–40 milliseconds apart or less.
Let’s jump into how we can reduce costly re-renders for gesture animations.
Typically, when we want to track a value in a React component, in this case, offsetY in the example below, the default strategy is to use setState when the value changes. This isn’t optimal since a small interaction will potentially trigger 20–30 events, resulting in 20–30 re-renders. This would cause many UI frames to be dropped, causing elements to jump across the screen unexpectedly, instead of a transitioning across in a fluid motion.
To avoid this, first, we are going to track the animated style value coming from our gesture event as an Animated.Value.
Next, when the onGestureEvent callback is fired, we use the setValue method from the Animate.Value instance to modify the native node directly.
import React, { Component } from 'react'; import { Animated, View } from 'react-native'; import { PanGestureHandler } from 'react-native-gesture-handler'; class GestureComponentExample extends Component { offsetY = new Animated.Value(0); onGestureEvent = (gestureEvent) => { const { nativeEvent } = gestureEvent; const { absoluteY: offsetY } = nativeEvent; this.offsetY.setValue(offsetY); } render() { const animatedStyle = { transform: [{ translateY: this.offsetY }] }; return ( <View style={styles.container}> <PanGestureHandler onGestureEvent={this.onGestureEvent}> <Animated.View style={[animatedStyle, styles.box]} /> </PanGestureHandler> </View> ) } } const styles = { container: { flex: 1 }, box: { height: 100, width: '100%', backgroundColor: 'black' } } export default GestureComponentExample;
This allows the box to be dragged up and down along the y-axis fluidly without dropping any frames. All without re-rendering the component.