Worklets, Shared Values und der UI-Thread im Detail
Reanimated 3 verlagert Animationen vom JS-Thread auf den UI-Thread und macht React Native Apps damit auch unter Last flüssig. Dieser Artikel erklärt Worklets, useSharedValue, useAnimatedStyle, runOnJS und runOnUI, die Bewegungsfunktionen withTiming, withSpring und withDecay sowie Layout-Animationen und interpolate() anhand konkreter Codebeispiele.
Inhaltsverzeichnis
- 1. Warum UI-Thread-Animationen zählen
- 2. Worklets und das UI-Thread-Ausführungsmodell
- 3. useSharedValue: reaktiver Zustand über Thread-Grenzen hinweg
- 4. useAnimatedStyle: deklarative Styles aus Shared Values
- 5. runOnJS und runOnUI: sicher zwischen Threads wechseln
- 6. withTiming, withSpring und withDecay: Bewegungskurven wählen
- 7. Layout-Animationen: entering, exiting und automatische Übergänge
- 8. interpolate(): Scroll- und Gesten-Werte auf visuelle Eigenschaften mappen
- 9. Reanimated 3 vs. die alte Animated API im Vergleich
- 10. Zusammenfassung
- 11. FAQ
1. Warum UI-Thread-Animationen zählen
React Native trennt seit jeher die Ausführung in mehrere Threads: Der JS-Thread führt die eigentliche Anwendungslogik aus, Render-Zyklen, Netzwerk-Callbacks und State-Updates, während der UI-Thread (auf iOS der Main-Thread, auf Android der UI-Thread des Betriebssystems) für das tatsächliche Zeichnen der nativen Views zuständig ist. Die klassische Animated-API von React Native konnte einen Teil der Animationen mit useNativeDriver: true auf den UI-Thread auslagern, war dabei aber auf eine begrenzte Menge an Properties beschränkt, im Wesentlichen transform und opacity. Sobald eine Animation von Zustand auf dem JS-Thread abhing, etwa einer Geste, die während eines Netzwerk-Requests verarbeitet wurde, musste bei jedem Frame ein Wert über die Bridge geschickt werden. Das kostet Zeit, und diese Zeit fehlt für 60 Bilder pro Sekunde.
Reanimated 3 löst dieses Problem grundlegend anders: Animationslogik läuft als sogenanntes Worklet direkt auf dem UI-Thread und ist damit von der Auslastung des JS-Thread entkoppelt. Wenn eine App im Hintergrund eine große JSON-Antwort parst, einen komplexen React-Baum neu rendert oder eine teure Berechnung durchführt, blockiert das den JS-Thread, nicht aber den UI-Thread. Eine Animation, die vollständig über Reanimated 3 läuft, bleibt in genau diesem Moment flüssig, während eine auf dem JS-Thread abhängige Animation ruckelt oder komplett einfriert. Das ist der zentrale Grund, warum Reanimated 3 heute der De-facto-Standard für Animationen in produktiven React-Native-Apps ist.
Technisch macht das die JSI (JavaScript Interface) möglich, die seit React Native 0.66 verfügbar ist und mit der neuen Architektur (Fabric, TurboModules) weiter ausgebaut wurde. Statt jede Kommunikation zwischen JS-Thread und nativer Seite über die asynchrone, serialisierende Bridge zu schicken, erlaubt JSI synchrone, direkte Funktionsaufrufe zwischen JavaScript und C++. Reanimated 3 baut genau darauf auf: Ein Worklet wird einmal auf den UI-Thread kompiliert und läuft dort danach unabhängig, ohne dass für jeden Animationsschritt ein Bridge-Round-Trip nötig ist. Das ist der Unterschied zwischen Animationen, die bei 60 oder gar 120 Hertz sauber laufen, und Animationen, die bei Last spürbar ruckeln.
2. Worklets und das UI-Thread-Ausführungsmodell
Ein Worklet ist eine JavaScript-Funktion, die mit der Direktive 'worklet' markiert wird und dadurch vom Reanimated-3-Babel-Plugin speziell behandelt wird. Das Plugin extrahiert den Funktionskörper zur Build-Zeit, serialisiert ihn in eine Form, die auch auf dem UI-Thread ausführbar ist, und hängt eine Referenz auf diese kompilierte Version an die Funktion an. Zur Laufzeit kann Reanimated 3 diese kompilierte Repräsentation dann direkt auf dem UI-Thread ausführen, unabhängig davon, was der JS-Thread gerade tut. Wichtig dabei: Ein Worklet läuft in einem eigenen, minimalen JavaScript-Kontext auf dem UI-Thread, nicht im selben Kontext wie die restliche App-Logik. Das erklärt, warum Closures über externe Variablen zwar funktionieren, aber kopiert statt referenziert werden, und warum Module wie Date oder große Bibliotheken innerhalb eines Worklets nur eingeschränkt nutzbar sind.
In der Praxis muss man selten explizit 'worklet' schreiben, weil viele Reanimated-3-APIs wie useAnimatedStyle oder useDerivedValue ihre Callback-Funktion automatisch als Worklet behandeln. Trotzdem ist das Konzept die Grundlage von allem, was in diesem Artikel folgt: useSharedValue, useAnimatedStyle, withTiming und withSpring funktionieren nur, weil im Hintergrund Worklets auf dem UI-Thread laufen und dort direkten Zugriff auf die nativen View-Properties haben. Damit dieser Mechanismus überhaupt funktioniert, muss das Babel-Plugin von Reanimated 3 korrekt eingebunden sein, und zwar als letztes Plugin in der Liste, weil es den Quellcode nach allen anderen Transformationen analysiert.
# Install Reanimated 3 (works with React Native 0.73 and newer)
npm install react-native-reanimated
# iOS only: install the native pods for the new architecture
cd ios && pod install && cd ..
# Clear the Metro cache after adding the Babel plugin below
npx react-native start --reset-cache
{
"presets": ["module:metro-react-native-babel-preset"],
"plugins": [
"react-native-reanimated/plugin"
]
}
Der Reanimated-3-Babel-Plugin-Eintrag muss in babel.config.js immer als letztes Element im plugins-Array stehen. Fehlt er oder steht er an falscher Stelle, werden Worklets nicht korrekt kompiliert, und Reanimated 3 wirft zur Laufzeit kryptische Fehler über fehlende Funktionen auf dem UI-Thread. Nach jeder Änderung an der Babel-Konfiguration ist ein vollständiger Neustart mit geleertem Metro-Cache nötig, ein einfaches Hot-Reload reicht nicht aus, weil die Worklet-Transformation nur beim initialen Bundling greift.
3. useSharedValue: reaktiver Zustand über Thread-Grenzen hinweg
useSharedValue ist der zentrale Baustein von Reanimated 3 und ersetzt in Animationskontexten den klassischen useState-Hook. Ein Shared Value ist ein Objekt mit genau einer Eigenschaft, .value, das sowohl vom JS-Thread als auch vom UI-Thread gelesen und geschrieben werden kann, ohne dass dabei ein React-Re-Render ausgelöst wird. Das ist der entscheidende Unterschied zu useState: Ein State-Update in React löst immer einen Render-Zyklus der Komponente aus, was für 60 Updates pro Sekunde völlig ungeeignet wäre. Ein Shared Value hingegen kann sich beliebig oft pro Sekunde ändern, ohne dass React davon überhaupt etwas mitbekommt.
Wird der Wert eines Shared Value auf dem UI-Thread verändert, etwa durch withSpring oder direkt durch eine Geste, reagieren alle davon abhängigen useAnimatedStyle-Aufrufe sofort und ebenfalls auf dem UI-Thread, ohne den Umweg über den JS-Thread. Das ist der Mechanismus, der Reanimated 3 so performant macht: Eine Kette aus Shared Value, Bewegungsfunktion und Animated Style bleibt vollständig auf dem UI-Thread und ist damit unabhängig von JS-Thread-Last. Ein Shared Value wird immer mit einem Initialwert erzeugt und bleibt über die gesamte Lebensdauer der Komponente stabil, ähnlich wie eine Ref, nur eben mit der Fähigkeit, den UI-Thread über Änderungen zu informieren.
Ein häufiges Missverständnis: Man liest den aktuellen Wert eines Shared Value niemals direkt im JSX oder in normalem Render-Code, sondern immer innerhalb eines Worklets, etwa in useAnimatedStyle oder useDerivedValue. Greift man stattdessen direkt in der Render-Funktion auf sharedValue.value zu, funktioniert das zwar syntaktisch, liefert aber nur den Wert zum Zeitpunkt des letzten Renders und aktualisiert sich nicht automatisch mit jedem Animationsschritt, weil Reanimated 3 gerade deswegen keinen Re-Render auslöst.
4. useAnimatedStyle: deklarative Styles aus Shared Values
useAnimatedStyle ist selbst ein Worklet und wird von Reanimated 3 automatisch immer dann neu ausgewertet, wenn sich einer der darin gelesenen Shared Values ändert. Das Ergebnis ist ein Style-Objekt, das direkt an eine Animated.View, Animated.Text oder eine andere von Reanimated 3 exportierte Komponente übergeben wird. Diese Auswertung passiert komplett auf dem UI-Thread, in genau dem Frame, in dem sich der Shared Value ändert, ohne einen einzigen Bridge-Aufruf und ohne dass die React-Komponente selbst neu rendert. Für den Entwickler fühlt sich das an wie normales React, für die Laufzeit ist es aber ein fundamental anderer, viel schnellerer Mechanismus.
Die Abhängigkeitserkennung von useAnimatedStyle funktioniert automatisch über statische Analyse des Callback-Codes, ein manuelles Dependency-Array wie bei useEffect gibt es nicht. Jeder Shared Value, der innerhalb des Callbacks über .value gelesen wird, wird automatisch als Abhängigkeit registriert. Das folgende Beispiel zeigt einen typischen Fade-In-Effekt, bei dem Opazität und eine leichte Verschiebung nach oben aus demselben Shared Value abgeleitet werden.
import Animated, {
useSharedValue,
useAnimatedStyle,
withTiming,
} from 'react-native-reanimated';
function FadeInBox({ children }) {
// Shared value lives on the UI thread, mutating it never triggers a re-render
const opacity = useSharedValue(0);
const animatedStyle = useAnimatedStyle(() => {
// This callback is a worklet: it runs on the UI thread, not the JS thread
return {
opacity: opacity.value,
transform: [{ translateY: (1 - opacity.value) * 20 }],
};
});
React.useEffect(() => {
opacity.value = withTiming(1, { duration: 400 });
}, []);
return <Animated.View style={[styles.box, animatedStyle]}>{children}</Animated.View>;
}
Wichtig ist, dass die einzelnen Style-Properties innerhalb des Callbacks berechnet werden, statt sie außerhalb vorzuberechnen und nur einzusetzen. Reanimated 3 analysiert genau den Code innerhalb der Funktion, um zu erkennen, welche Shared Values referenziert werden. Wird ein Zwischenwert außerhalb der Funktion berechnet und nur das Ergebnis übergeben, verliert Reanimated 3 die Reaktivität, und die Animation friert beim ersten gerenderten Wert ein.
5. runOnJS und runOnUI: sicher zwischen Threads wechseln
Worklets laufen in einem eigenen Kontext auf dem UI-Thread und haben deshalb keinen direkten Zugriff auf normale JavaScript-Funktionen, die im JS-Thread-Kontext definiert wurden, etwa setState, Navigation-Aufrufe oder API-Calls. Genau dafür gibt es runOnJS: Die Funktion nimmt eine normale JS-Funktion entgegen und plant deren Ausführung auf dem JS-Thread ein, aufgerufen aus einem Worklet heraus. Ein typischer Anwendungsfall ist eine Geste, die vollständig auf dem UI-Thread verarbeitet wird, aber am Ende, etwa beim Loslassen, einen State-Update im JS-Thread auslösen soll, um zum Beispiel eine Karte aus einer Liste zu entfernen oder eine Analytics-Aktion zu feuern.
Der umgekehrte Fall wird von runOnUI abgedeckt: Aus dem JS-Thread heraus wird ein Worklet explizit zur Ausführung auf dem UI-Thread eingeplant. Das ist seltener nötig, weil die meisten Reanimated-3-Hooks das automatisch übernehmen, wird aber relevant, wenn man mehrere Shared Values in einem einzigen, synchronen Block auf dem UI-Thread aktualisieren möchte, um Zwischenzustände zu vermeiden. Ein Beispiel wäre das gleichzeitige Zurücksetzen von Position, Skalierung und Opazität am Ende einer komplexen Gesteninteraktion, ohne dass zwischen den einzelnen Zuweisungen ein sichtbarer Zwischenframe entsteht.
Ein häufiger Performance-Fehler ist der übermäßige Einsatz von runOnJS: Wird bei jedem einzelnen Animationsframe eine Funktion auf den JS-Thread geschickt, etwa um eine Fortschrittsanzeige als Text zu aktualisieren, entsteht wieder genau das Bridge-Ping-Pong, das Reanimated 3 eigentlich vermeiden soll. Statt bei jedem Frame runOnJS aufzurufen, sollte man, wo möglich, den Zielwert direkt als Shared Value führen und die visuelle Repräsentation über useAnimatedStyle oder useAnimatedProps ableiten, statt über React-State und Re-Renders zu gehen.
6. withTiming, withSpring und withDecay: Bewegungskurven wählen
Reanimated 3 stellt drei zentrale Bewegungsfunktionen bereit, die jeweils einen anderen Charakter von Animation erzeugen. withTiming animiert einen Shared Value über eine feste Dauer mit einer definierbaren Easing-Kurve, zum Beispiel Easing.out(Easing.cubic), und eignet sich für Übergänge, die einen vorhersehbaren, gleichmäßigen Zeitrahmen haben sollen, etwa das Ein- und Ausblenden eines Modals. withSpring hingegen basiert auf einem physikalischen Feder-Modell mit den Parametern damping, stiffness und mass, statt auf einer festen Dauer. Das Ergebnis wirkt organischer und reagiert natürlicher auf Interaktion, weil die Animation nicht nach einer festen Zeit abrupt endet, sondern in eine Ruheposition einschwingt.
withDecay deckt einen dritten Fall ab: Bewegungen, die auf einer Anfangsgeschwindigkeit basieren und über die Zeit abgebremst werden, klassischerweise nach einem Fling-Gesture beim Scrollen oder Swipen. Statt einen Zielwert vorzugeben, übergibt man velocity und optional clamp, um den erlaubten Wertebereich zu begrenzen, und Reanimated 3 berechnet daraus die Ausklingkurve. Alle drei Funktionen geben selbst wieder einen animierbaren Wert zurück, der einem Shared Value zugewiesen wird, und alle drei akzeptieren einen optionalen Callback als zweites beziehungsweise drittes Argument, der beim Abschluss der Animation aufgerufen wird, typischerweise in Kombination mit runOnJS, wenn danach JS-seitige Logik folgen soll.
import { Pressable } from 'react-native';
import Animated, {
useSharedValue,
useAnimatedStyle,
withSpring,
} from 'react-native-reanimated';
function ScaleButton({ onPress, children }) {
const scale = useSharedValue(1);
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ scale: scale.value }],
}));
const handlePressIn = () => {
// Spring physics: damping and stiffness define how it settles
scale.value = withSpring(0.92, { damping: 14, stiffness: 180 });
};
const handlePressOut = () => {
scale.value = withSpring(1, { damping: 14, stiffness: 180 });
};
return (
<Animated.View style={animatedStyle}>
<Pressable onPressIn={handlePressIn} onPressOut={handlePressOut} onPress={onPress}>
{children}
</Pressable>
</Animated.View>
);
}
Die Wahl der richtigen Bewegungsfunktion hat spürbaren Einfluss auf das Gefühl einer App. Ein Preisänderungs-Badge im Warenkorb, das per withSpring leicht überschwingt, fühlt sich lebendiger an als eines, das mit fester Dauer über withTiming einfach linear einblendet. Für Fortschrittsbalken, Ladeindikatoren und alles mit einer klar definierten Zieldauer bleibt withTiming jedoch die richtige Wahl, weil hier Vorhersehbarkeit wichtiger ist als organische Bewegung.
7. Layout-Animationen: entering, exiting und automatische Übergänge
Neben der klassischen Style-Animation über useAnimatedStyle bietet Reanimated 3 ein deklaratives System für Layout-Animationen, das drei Ereignisse abdeckt: das Einfügen einer Komponente (entering), das Entfernen einer Komponente (exiting) und die Änderung von Position oder Größe einer weiterhin sichtbaren Komponente (layout). Statt manuell Shared Values zu verwalten, reicht es, einer Animated.View die passende Preset-Animation als Prop zu übergeben, etwa entering={FadeIn} oder exiting={SlideOutLeft}. Reanimated 3 übernimmt dann automatisch die Messung der Ausgangs- und Zielposition sowie die eigentliche Interpolation, komplett auf dem UI-Thread.
Das layout-Prop ist besonders nützlich in Listen: Wird ein Element aus einer FlatList oder einer manuell gemappten Liste von Produktkarten entfernt, animieren alle nachfolgenden Elemente automatisch in ihre neue Position, statt abrupt zu springen. Presets wie Layout.springify() lassen sich mit denselben Feder-Parametern konfigurieren wie withSpring, etwa .damping(16), um die Übergänge an den Rest der Animationen einer App anzupassen. Vor Reanimated 3 war so etwas nur über die deutlich fehleranfälligere, plattformübergreifend inkonsistente LayoutAnimation-API von React Native möglich, die auf Android historisch viele Randfälle nicht korrekt abgedeckt hat.
import Animated, { FadeOut, Layout, SlideInRight } from 'react-native-reanimated';
function ProductRow({ product, onRemove }) {
return (
<Animated.View
entering={SlideInRight.duration(300)}
exiting={FadeOut.duration(200)}
layout={Layout.springify().damping(16)}
style={styles.row}
>
<Text>{product.name}</Text>
<Pressable onPress={() => onRemove(product.id)}>
<Text>Remove</Text>
</Pressable>
</Animated.View>
);
}
Ein wichtiger Punkt für den Warenkorb oder die Produktliste eines Mobile-Commerce-Shops: Layout-Animationen greifen automatisch, wenn Elemente über den React-Key korrekt identifiziert werden. Fehlt ein stabiler Key oder wird ein Index als Key missbraucht, erkennt Reanimated 3 nicht zuverlässig, welches Element entfernt und welches nur verschoben wurde, und die Übergänge wirken sprunghaft statt flüssig.
8. interpolate(): Scroll- und Gesten-Werte auf visuelle Eigenschaften mappen
Viele der überzeugendsten Animationen in mobilen Apps sind keine eigenständigen Animationen, sondern Ableitungen aus einem bereits vorhandenen Wert, etwa der Scroll-Position oder der Fingerbewegung während einer Geste. Genau dafür ist interpolate() gedacht: Die Funktion nimmt einen Eingabewert, ein Eingabe-Wertebereich (inputRange) und einen Ausgabe-Wertebereich (outputRange) entgegen und berechnet, wo innerhalb des Ausgabebereichs der aktuelle Wert liegt. Ein Scroll-Offset von 0 bis 200 Pixel lässt sich so direkt auf eine Opazität von 1 bis 0 oder eine Skalierung von 1 auf 0.8 abbilden, ohne eine eigene Timing- oder Feder-Animation zu benötigen.
In Kombination mit useAnimatedScrollHandler entsteht daraus ein vollständig UI-Thread-basierter Scroll-Effekt: Der Scroll-Handler schreibt die aktuelle Scroll-Position in einen Shared Value, und ein useAnimatedStyle-Callback ruft darin interpolate(scrollY.value, [0, 100], [1, 0.9], Extrapolate.CLAMP) auf, um zum Beispiel einen Produktbild-Header beim Scrollen sanft zu verkleinern. Der Extrapolate.CLAMP-Parameter verhindert dabei, dass der Wert über den definierten Ausgabebereich hinausschießt, wenn der Eingabewert den definierten Bereich verlässt, etwa bei Overscroll auf iOS.
Derselbe Mechanismus funktioniert für Gesten: Die horizontale Verschiebung eines Swipe-to-Dismiss-Gesture, verarbeitet über den Gesture Handler und in einem Shared Value gehalten, lässt sich per interpolate gleichzeitig auf Opazität, Rotation und Skalierung einer Karte abbilden. Alle diese Ableitungen laufen synchron im selben UI-Thread-Frame wie die Geste selbst, ohne einen einzigen Zwischenschritt über den JS-Thread. Das ist der Grund, warum Swipe-Interaktionen mit Reanimated 3 spürbar direkter wirken als vergleichbare Umsetzungen mit der alten Animated-API.
9. Reanimated 3 vs. die alte Animated API im Vergleich
Der Umstieg von der eingebauten Animated-API auf Reanimated 3 betrifft nicht nur die Syntax, sondern die grundlegende Ausführungsarchitektur einer Animation. Die folgende Tabelle stellt die wichtigsten Unterschiede gegenüber, bevor im Anschluss die häufigsten Performance-Fallen im Umgang mit Reanimated 3 selbst behandelt werden.
| Dimension | Animated API (alt) | Reanimated 3 | Vorteil |
|---|---|---|---|
| Ausführungs-Thread | JS-Thread, Bridge-Serialisierung pro Frame | UI-Thread via Worklets und JSI | Kein Bridge-Round-Trip, stabil bei JS-Last |
| Gesten-Integration | Getrennter Kontext, viel manuelles Verdrahten | Gesture Handler teilt Shared Values direkt | Geste und Animation im selben Frame |
| Native-Driver-Limitationen | Nur transform und opacity nativ animierbar | Praktisch alle Properties auf dem UI-Thread | Keine Property-Whitelist mehr nötig |
| Layout-Animationen | Globale LayoutAnimation-API, auf Android instabil | Deklarative entering/exiting/layout pro Komponente | Granulare, zuverlässige Kontrolle |
| Developer-Ergonomie | Imperative Interpolate-Ketten, viel Boilerplate | Deklarative Hooks, kompakter, lesbarer Code | Weniger Code, weniger Fehlerquellen |
Auch mit Reanimated 3 selbst entstehen typische Performance-Fallen. Die häufigste: das direkte Lesen von sharedValue.value im JS-Thread, etwa direkt in einer Render-Funktion oder einem normalen useEffect, um einen Wert in State zu übernehmen. Das erzwingt eine synchrone Thread-Grenzüberschreitung und untergräbt genau den Vorteil, den Shared Values eigentlich bieten sollen. Der zweite häufige Fehler ist das unnötige Auslösen von React-Re-Renders während einer laufenden Animation, etwa durch einen runOnJS-Aufruf bei jedem Frame, statt visuelle Effekte konsequent über useAnimatedStyle und useAnimatedProps abzubilden. Beide Fallen führen dazu, dass eine mit Reanimated 3 gebaute Animation am Ende trotzdem wieder vom JS-Thread abhängt und ruckelt, sobald dieser unter Last gerät.
Mironsoft
React Native Apps für Magento-basierte Commerce-Shops
Mobile Commerce, das sich flüssig anfühlt?
Wir bauen React-Native-Storefronts, die an euren Magento-Shop angebunden sind, mit Reanimated 3 für Produktkarten, Warenkorb-Übergänge und Gesten, die sich nativ anfühlen statt wie eine Web-Ansicht in einer App-Hülle.
UI-Performance-Audit
Analyse von JS-Thread-Last, Re-Renders und Animationsarchitektur eurer bestehenden App
Animations-Design
Worklet-basierte Übergänge, Layout-Animationen und Gesten mit Reanimated 3
App-Feinschliff
Von der ersten Produktliste bis zum poliertem Checkout-Flow mit 60fps-Anspruch
10. Zusammenfassung
Reanimated 3 verändert grundlegend, wie Animationen in React Native ausgeführt werden. Statt bei jedem Frame über die Bridge zu kommunizieren, laufen Worklets direkt auf dem UI-Thread und bleiben damit unabhängig von der Auslastung des JS-Thread. useSharedValue hält reaktiven Zustand, der Änderungen mitteilt, ohne einen React-Re-Render auszulösen, und useAnimatedStyle übersetzt diesen Zustand deklarativ in Styles, die ebenfalls vollständig auf dem UI-Thread berechnet werden. runOnJS und runOnUI bilden die kontrollierten Übergänge zwischen den beiden Welten, für die seltenen Fälle, in denen ein Wechsel wirklich nötig ist.
Die Bewegungsfunktionen withTiming, withSpring und withDecay decken zusammen die meisten Animationsbedürfnisse ab, von zeitbasierten Übergängen über physikalisch wirkende Federbewegungen bis hin zu geschwindigkeitsbasierten Ausklingeffekten. Layout-Animationen mit entering, exiting und layout ersetzen die fehleranfällige alte LayoutAnimation-API, und interpolate() verbindet Scroll- und Gesten-Werte direkt mit visuellen Eigenschaften. Wer die typischen Fallen vermeidet, allen voran das Lesen von Shared Values im JS-Thread und unnötige runOnJS-Aufrufe pro Frame, bekommt mit Reanimated 3 Animationen, die auch unter realer App-Last bei 60 Bildern pro Sekunde bleiben.
Reanimated 3: Das Wichtigste auf einen Blick
Worklets & UI-Thread
Mit 'worklet' markierte Funktionen laufen kompiliert auf dem UI-Thread und bleiben unabhängig von JS-Thread-Last.
Shared Values & Styles
useSharedValue hält Zustand ohne Re-Render, useAnimatedStyle leitet daraus reaktiv Styles ab.
Bewegungsfunktionen
withTiming für feste Dauer, withSpring für physikalisches Einschwingen, withDecay für Fling-Bewegungen.
Layout & Interpolation
entering/exiting/layout für automatische Übergänge, interpolate() für Scroll- und Gesten-Mapping.