Skip to content

Instantly share code, notes, and snippets.

@terrysahaidak
Last active February 16, 2023 14:16
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save terrysahaidak/cf8c155c583f72acfcb2dbe5ea9bbe48 to your computer and use it in GitHub Desktop.
Save terrysahaidak/cf8c155c583f72acfcb2dbe5ea9bbe48 to your computer and use it in GitHub Desktop.
Reanimated Worklets explanation
import React from 'react';
import { Text, View, Dimensions } from 'react-native';
import Animated, {
useSharedValue,
useWorklet,
useEventWorklet,
} from 'react-native-reanimated';
import { PanGestureHandler } from 'react-native-gesture-handler';
import { getStatusBarHeight } from 'react-native-status-bar-height';
function MichalApp() {
// those all are animated values
// but now they're connected to some background JS VM as well as the main one
// so this is kinda in-background-thread-executable animated values
// everything possible by TurboModules and JSI
const prevX = useSharedValue(0);
const prevY = useSharedValue(0);
const totalX = useSharedValue(0);
const totalY = useSharedValue(0);
const velocityX = useSharedValue(0);
const velocityY = useSharedValue(0);
const parentWidth = useSharedValue(Dimensions.get('window').width);
const parentHeight = useSharedValue(
Dimensions.get('window').height - getStatusBarHeight(true)
);
// this is kinda decay animation implementation
// you can only use values callback provides you
// nothing from the outside
// you're passing them as deps to this hook
const movable = useWorklet(
function(velocityX, velocityY, totalX, totalY, parentHeight, parentWidth) {
'worklet';
// you're able to do any kind of stuff here
// everything will be run in background
// and that function fill be executed on each frame
// kinda "requestAnimationFrame" thing
// just some regular JS here
const cords = [
{
velocity: velocityX,
total: totalX,
dim: parentWidth,
},
{
velocity: velocityY,
total: totalY,
dim: parentHeight,
},
];
for (const cord of cords) {
const { velocity, total, dim } = cord;
if (Math.abs(velocity.value) > 0.01) {
// each shared value's got .value – getter of the stored value
// also "set" to set the new one
total.set(total.value + velocity.value / 60);
velocity.set(velocity.value * 0.99);
if (total.value < 0) {
total.set(-total.value);
velocity.set(-velocity.value);
}
if (total.value + 40 > dim.value) {
// and yes, you can create some temp variables
// just in the middle of execution
const excess = total.value + 40 - dim.value;
total.set(total.value - 2 * excess);
velocity.set(-velocity.value);
}
}
}
if (
Math.abs(velocityX.value) < 0.01 &&
Math.abs(velocityY.value) < 0.01
) {
// not sure what this means
return true;
}
// you should pass all of the shared values to be able to use them
},
[velocityX, velocityY, totalX, totalY, parentHeight, parentWidth]
);
// this is the event handler
// kinda Animated.event() with an arrow function instead of just mapping values expression
// so this event thing will be executed on each event
const worklet = useEventWorklet(
function(prevX, prevY, totalX, totalY, ruszable, velocityX, velocityY) {
'worklet';
// event is available under the `this`
// so you can't use arrow functions
// this is basically gesture handler event
if (this.event.state === 2) {
prevX.set(totalX.value);
prevY.set(totalY.value);
// you have control all the worklets here
// so you can "stop" any worklet
this.stop(movable);
}
totalX.set(this.event.translationX + prevX.value);
totalY.set(this.event.translationY + prevY.value);
if (this.event.state === 5) {
velocityX.set(this.event.velocityX);
velocityY.set(this.event.velocityY);
// and run it, of course
// run means it's gonna be executed on each frame
this.start(movable);
}
},
[prevX, prevY, totalX, totalY, movable, velocityX, velocityY]
);
return (
<View style={{ flex: 1 }}>
<PanGestureHandler
// just as a regular event
onGestureEvent={worklet}
onHandlerStateChange={worklet}>
<Animated.View
style={{
width: 40,
height: 40,
transform: [
{
// and regular values here
translateX: totalX,
},
{
translateY: totalY,
},
],
backgroundColor: 'black',
}}
/>
</PanGestureHandler>
</View>
);
}
export default MichalApp;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment