Animations
Evil Bridges and Blocked Threads

Thupi Ceylons
Software Engineer at Danske Bank

I <3 awesome software!
Fast
Smooth
Aesthetic


Fast
Smooth
Aesthetic
Thats why we use React Native!

Why use React Native?
Cross Platform
Web Technology (Javascript)
ReactJS like
What sucks about React Native?
Javascript Runtime
Layouting Overhead
Data Serialization
Performance


This is really the reason im giving this talk



So why is React Native slow

The Evil Async Bridge
Bridge

Async is as virus

60 FPS
Declarative
declarative programming focuses on what the program should accomplish.
Benefits:
Easy to Optimize
Imperative
Imperative programming focuses on describing how a program operates.
Benefits:
Easy to describe complex operations.
import { Animated } from 'react-native';Let's take a deeper look
import React from "react";
import { Animated, TouchableOpacity, Text } from "react-native";
export default class AnimatedBox extends React.Component {
animatedValue = new Animated.Value(0);
handlePress = () => {
Animated.spring(this.animatedValue, {
toValue: 100,
tension: 30,
friction: 12,
useNativeDriver: true
}).start();
};
render() {
const style = {
height: 100,
width: 100,
backgroundColor: "red"
};
const animatedStyle = {
transform: [{ translateX: this.animatedValue }]
};
return (
<Animated.View style={animatedStyle}>
<TouchableOpacity style={style} onPress={this.handlePress}>
<Text>Press here</Text>
</TouchableOpacity>
</Animated.View>
);
}
}
import React from "react";
import { Animated, View, PanResponder } from "react-native";
export default class AnimatedBox extends React.Component {
translateX = new Animated.Value(1);
translateXValue = 0;
translateY = new Animated.Value(1);
translateYValue = 0;
responder = PanResponder.create({
...
});
componentDidMount() {
this.translateY.addListener(({ value }) => {
this.translateYValue = value;
});
this.translateX.addListener(({ value }) => {
this.translateXValue = value;
});
}
render() {
const style = {
...
};
return <Animated.View style={style} {...this.responder.panHandlers} />;
}
}
export default class AnimatedBox extends React.Component {
translateX = new Animated.Value(1);
translateXValue = 0;
translateY = new Animated.Value(1);
translateYValue = 0;
responder = PanResponder.create({
onMoveShouldSetPanResponder: (e, gestureState) => true,
onPanResponderGrant: () => {
this.translateY.setOffset(this.translateYValue);
this.translateY.setValue(0);
this.translateX.setOffset(this.translateXValue);
this.translateX.setValue(0);
},
onPanResponderMove: (e, gestureState) => {
this.translateY.setValue(gestureState.dy);
this.translateX.setValue(gestureState.dx);
},
onPanResponderRelease: (e, gestureState) => {
this.translateY.flattenOffset();
this.translateX.flattenOffset();
}
});
componentDidMount() {
this.translateY.addListener(({ value }) => {
this.translateYValue = value;
});
this.translateX.addListener(({ value }) => {
this.translateXValue = value;
});
}
...
}
The problem is Async
The JS thread might be blocked

Just use useNativeDriver!
Not really, PanResponder is written in JS
The main takeaway

Do not cross the evil bridge unless necessary!
So what can we do...
react-native-gesture-handler
by Krzysztof Magiera
import {
Animated
} from "react-native";
import { PanGestureHandler, State } from "react-native-gesture-handler";
export class Swipeable extends Component {
// ...
_onHandlerStateChange = ({ nativeEvent }) => {
if (nativeEvent.oldState === State.ACTIVE) {
// ...
}
};
render() {
// ...
return (
<View style={[styles.root, style]} onLayout={this.handleLayout}>
<PanGestureHandler
ref={this.swipeable}
shouldCancelWhenOutside={false}
onGestureEvent={this._onGestureEvent}
onHandlerStateChange={this._onHandlerStateChange}
>
{/* ... */}
</PanGestureHandler>
</View>
);
}
}import { Animated, PanResponder } from "react-native";
export class Swipeable extends Component {
// ...
panResponder = PanResponder.create({
onMoveShouldSetPanResponderCapture: (evt, gestureState) => {
const dx = Math.abs(gestureState.dx);
const dy = Math.abs(gestureState.dy);
return dx > dy && dx > X_AXIS_CAPTURE_THRESHOLD;
},
onMoveShouldSetPanResponder: () => false,
onPanResponderTerminationRequest: () => false,
onPanResponderRelease: this.handleTouchEnd,
onPanResponderTerminate: this.handleTouchEnd,
onPanResponderMove: this.handleTouchMove,
onPanResponderGrant: this.handleTouchStart
});
handleTouchStart = (event, gestureState) => { ... };
handleTouchMove = (event, gestureState) => { ... };
handleTouchEnd = (event, gestureState) => { ... };
render() {
// ...
return (
<View style={[styles.root, style]} onLayout={this.handleLayout}>
<Animated.View
{...this.panResponder.panHandlers}
style={[styles.container, containerStyle, sceneContainerStyle]}
>
{/* ... */}
</Animated.View>
</View>
);
}
}
Original Swipeable
New Swipeable
Original Swipeable
New Swipeable


Features that cannot be achived by Animated
render() {
return (
<PanGestureHandler
activeOffsetY={-20}
onGestureEvent={this.handelScaleGesture}
>
<PanGestureHandler
activeOffsetY={20}
onGestureEvent={this.handelTranslateGesture}
>
<View style={{
height: 150,
justifyContent: 'center',
}}>
{/* ... */}
</View>
</PanGestureHandler>
</PanGestureHandler>
);
}Bonus
react-native-reanimated
by Krzysztof Magiera
return (
<PanGestureHandler
onGestureEvent={event([
{
nativeEvent: ({ translationX: x, translationY: y, state }) => block([
set(this._transX, add(x, offsetX)),
set(this._transY, add(y, offsetY)),
cond(
eq(state, State.END),
[
set(this.offsetX, add(this.offsetX, x)),
set(this.offsetY, add(this.offsetY, y))
]
)
])
},
])}
>
<Animated.View
style={{
transform: [{
translateX: this._transX, translateY: this._transY }]
}
}
/>
</PanGestureHandler>
);Declarative logic in Animations
Thank you :-) !
Catch me at: THCE@danskebank.dk
Source code: https://github.com/thupi/db-rn-animations
Animations, Evil Bridges and Blocked Threads
By thupi
Animations, Evil Bridges and Blocked Threads
- 387