De stabiele release van React Native Reanimated 4 is, eerlijk gezegd, de grootste verschuiving in animaties sinds worklets in versie 2 hun intrede deden. De nieuwe versie brengt een declaratieve CSS-stijl animatie API, splitst worklets af in een aparte react-native-worklets package en — dit is belangrijk — ondersteunt uitsluitend de Nieuwe Architectuur. In deze gids voor 2026 laat ik je zien hoe je de nieuwe CSS API combineert met klassieke worklets, hoe je veilig migreert vanaf Reanimated 3 en (minstens zo handig) hoe je de meest voorkomende valkuilen ontwijkt.
Dus, laten we erin duiken.
Wat is er nieuw in Reanimated 4?
Reanimated 4.0 (stabiele release medio 2025, breed geadopteerd in 2026) is geen klein onderhoud — het is een fundamentele herziening die de bibliotheek toekomstbestendig maakt. De belangrijkste vernieuwingen op een rij:
- CSS animaties en transitions — een declaratieve API voor de pakweg 80% van de animaties die door state-veranderingen getriggerd worden.
- Worklets in een eigen package (
react-native-worklets) zodat ook andere libraries de worklet-runtime kunnen gebruiken. - Alleen Nieuwe Architectuur — Fabric en bridgeless mode zijn verplicht (React Native 0.76 of hoger).
- Verbeterde gesture-integratie met
react-native-gesture-handlerv3. - Cross-platform consistentie — spring fysica en interpolatie gedragen zich nu écht identiek op iOS en Android.
- Volledige terugwaartse compatibiliteit met de worklet-API uit v2/v3. Geen massale herschrijving dus.
Eerlijk? Dat laatste punt was voor mij het grootste opluchtende moment. Ik had me al schrap gezet voor een herschrijfmarathon, maar het bleef beperkt tot een paar configuratiewijzigingen.
Vereisten en installatie
Voor je Reanimated 4 installeert, even een snelle check of je project aan de minimale eisen voldoet:
- React Native 0.76 of hoger met de Nieuwe Architectuur ingeschakeld (Fabric).
- React 19 of hoger.
- Voor Expo: SDK 54 of hoger.
- iOS 15.1+ en Android API 24+.
Installatiestappen
# Installeer Reanimated 4 en de nieuwe worklets package
npx expo install react-native-reanimated react-native-worklets
# Voor pure React Native projecten:
npm install react-native-reanimated react-native-worklets
cd ios && pod install
Update vervolgens je babel.config.js — de plugin is verhuisd (let hierop, dit is de #1 fout die mensen maken):
// babel.config.js
module.exports = function (api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
plugins: [
// VERWIJDER: 'react-native-reanimated/plugin'
'react-native-worklets/plugin', // NIEUW in v4
],
};
};
En vergeet alsjeblieft je Metro-cache niet te wissen na deze wijziging. Ik heb een keer twintig minuten zitten staren naar een "rare bug" die simpelweg een stale cache was:
npx expo start -c
# of voor pure RN:
npx react-native start --reset-cache
De nieuwe CSS Animaties API
Het belangrijkste pluspunt van Reanimated 4? Wat mij betreft de CSS-stijl declaratieve API. In plaats van een shared value en een useAnimatedStyle worklet te schrijven voor een simpele fade-in, kun je nu rechtstreeks in je stijlobject een transition declareren — net zoals op het web. Het scheelt zoveel boilerplate dat het bijna verdacht voelt.
CSS Transitions: state-gestuurde animaties
import { useState } from 'react';
import { Pressable, Text } from 'react-native';
import Animated from 'react-native-reanimated';
export default function ToggleBox() {
const [active, setActive] = useState(false);
return (
<Pressable onPress={() => setActive(!active)}>
<Animated.View
style={{
width: active ? 200 : 100,
height: 100,
backgroundColor: active ? '#3b82f6' : '#e5e7eb',
transitionProperty: ['width', 'backgroundColor'],
transitionDuration: 300,
transitionTimingFunction: 'ease-in-out',
}}
/>
</Pressable>
);
}
Geen useSharedValue, geen useAnimatedStyle, geen withTiming. De style-verandering wordt automatisch geïnterpoleerd op de UI thread. Het is bijna saai hoe makkelijk dit is geworden.
CSS Keyframe Animaties
Voor herhaalde animaties (denk aan een laad-spinner of pulserende knop) gebruik je animationName met keyframes:
import Animated from 'react-native-reanimated';
const pulse = {
'0%': { transform: [{ scale: 1 }], opacity: 1 },
'50%': { transform: [{ scale: 1.1 }], opacity: 0.8 },
'100%': { transform: [{ scale: 1 }], opacity: 1 },
};
export function PulsingDot() {
return (
<Animated.View
style={{
width: 24,
height: 24,
borderRadius: 12,
backgroundColor: '#ef4444',
animationName: pulse,
animationDuration: 1200,
animationIterationCount: 'infinite',
animationTimingFunction: 'ease-in-out',
}}
/>
);
}
Wanneer kies je CSS en wanneer worklets?
De Reanimated-makers hanteren een vrij duidelijke vuistregel — en die werkt in de praktijk goed:
| Gebruik CSS animaties voor | Gebruik worklets voor |
|---|---|
| Modals, tooltips, snackbars in en uit faden | Pan/swipe gestures (kaarten slepen) |
| Accordion uitklappen, dropdowns | Scroll-gestuurde animaties (parallax) |
| Knop hover/pressed states | Gekoppelde animaties met afgeleide waarden |
| Tab-indicator verschuiven | Custom physics simulaties |
Twijfel je? Begin met CSS. Loop je tegen een limiet aan, schakel dan over op worklets. Niet andersom.
Worklets en shared values: nog steeds onmisbaar
Voor gesture-driven interacties blijft de klassieke worklet-API koning. Hier is een complete swipe-to-dismiss kaart met useSharedValue, useAnimatedStyle en withSpring:
import Animated, {
useSharedValue,
useAnimatedStyle,
withSpring,
runOnJS,
} from 'react-native-reanimated';
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
export default function SwipeCard({ onDismiss }) {
const translateX = useSharedValue(0);
const opacity = useSharedValue(1);
const pan = Gesture.Pan()
.onUpdate((event) => {
translateX.value = event.translationX;
opacity.value = 1 - Math.abs(event.translationX) / 400;
})
.onEnd((event) => {
if (Math.abs(event.translationX) > 150) {
translateX.value = withSpring(event.translationX > 0 ? 500 : -500);
opacity.value = withSpring(0);
runOnJS(onDismiss)();
} else {
translateX.value = withSpring(0);
opacity.value = withSpring(1);
}
});
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ translateX: translateX.value }],
opacity: opacity.value,
}));
return (
<GestureDetector gesture={pan}>
<Animated.View style={[styles.card, animatedStyle]} />
</GestureDetector>
);
}
Belangrijke regel: objectreferenties bij shared values
Een hardnekkige fout (waar ik zelf óók is in getuind) is het muteren van een eigenschap op een shared value object. Reanimated detecteert dat namelijk niet:
const sv = useSharedValue({ x: 0, y: 0 });
// FOUT: Reanimated verliest reactiviteit
sv.value.x = 50;
// CORRECT: vervang het hele object
sv.value = { x: 50, y: 0 };
Migratie van Reanimated 3 naar 4
Het goede nieuws: de meeste v3-code blijft onveranderd werken in v4. Toch zijn er een paar breaking changes waar je rekening mee moet houden — gelukkig redelijk overzichtelijk.
1. Babel plugin verplaatst
Wijzig 'react-native-reanimated/plugin' naar 'react-native-worklets/plugin' in babel.config.js. Mis je deze stap, dan krijg je deze foutmelding (die je waarschijnlijk al eens voorbij hebt zien komen):
[Reanimated] Seems like you are using a Babel plugin
`react-native-reanimated/plugin`. It was moved to
`react-native-worklets` package.
2. Hernoemde worklet-functies
De volgende functies zijn verhuisd naar react-native-worklets en hebben nieuwe namen gekregen. De oude namen werken nog (deprecated), maar verdwijnen in een toekomstige release:
runOnJS→scheduleOnRNrunOnUI→scheduleOnUIexecuteOnUIRuntimeSync→runOnUISync(en zonder die dubbele functie-aanroep, gelukkig)
3. withSpring drempelparameters
De fysica van withSpring is herschreven. restDisplacementThreshold en restSpeedThreshold zijn vervangen door één energyThreshold. De duration parameter is nu "perceptueel" (ongeveer 1.5× de werkelijke tijd, dus reken even na bij bestaande timings).
// v3
sv.value = withSpring(100, {
restDisplacementThreshold: 0.01,
restSpeedThreshold: 2,
});
// v4
sv.value = withSpring(100, {
energyThreshold: 6e-9,
});
4. Verwijderde APIs
useWorkletCallback— weg. Gebruik gewone worklet-functies.combineTransition— weg.addWhitelistedNativePropsenaddWhitelistedUIProps— zijn no-ops geworden. Je kunt ze veilig uit je codebase strippen.
5. Nieuwe Architectuur verplicht
Draait je app nog op de oude (Paper) renderer? Dan moet je eerst migreren naar Fabric voor je v4 kunt gebruiken. Update app.json:
{
"expo": {
"newArchEnabled": true
}
}
Voor pure React Native projecten zet je de flag in android/gradle.properties:
newArchEnabled=true
Performance optimalisatie tips
Reanimated 4 levert standaard prima prestaties, maar deze patronen helpen frame drops voorkomen op zwakkere apparaten:
- Scheid statische en dynamische stijlen. Plaats alleen de animerende eigenschappen in
useAnimatedStyle; de rest inStyleSheet.create. - Vermijd JavaScript-thread werk in worklets. Gebruik
scheduleOnRN(voorheenrunOnJS) sparzaam — elke aanroep brengt thread-overhead met zich mee. - Hergebruik shared values. Maak ze niet aan binnen render-cycles; declareer ze op componentniveau.
- Gebruik
useDerivedValuevoor afgeleide animaties in plaats van meerdere shared values handmatig te synchroniseren. - Schakel
removeClippedSubviewsin bij lange lijsten met geanimeerde items.
Praktijkvoorbeeld: een interactieve bottom sheet
Een veelgebruikt patroon dat zowel CSS animaties als worklets combineert. Dit is precies het soort component dat in Reanimated 3 nog wat omslachtig was, maar in v4 een stuk soepeler voelt:
import { useState } from 'react';
import { Dimensions, Pressable } from 'react-native';
import Animated, {
useSharedValue,
useAnimatedStyle,
withSpring,
} from 'react-native-reanimated';
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
const { height } = Dimensions.get('window');
const SHEET_HEIGHT = height * 0.6;
export default function BottomSheet({ children }) {
const translateY = useSharedValue(SHEET_HEIGHT);
const [isOpen, setIsOpen] = useState(false);
const open = () => {
translateY.value = withSpring(0, { damping: 20 });
setIsOpen(true);
};
const close = () => {
translateY.value = withSpring(SHEET_HEIGHT, { damping: 20 });
setIsOpen(false);
};
const pan = Gesture.Pan()
.onUpdate((e) => {
translateY.value = Math.max(0, e.translationY);
})
.onEnd((e) => {
if (e.translationY > 150) {
translateY.value = withSpring(SHEET_HEIGHT);
} else {
translateY.value = withSpring(0);
}
});
const sheetStyle = useAnimatedStyle(() => ({
transform: [{ translateY: translateY.value }],
}));
return (
<>
<Pressable onPress={open} style={styles.trigger}>
<Text>Open Sheet</Text>
</Pressable>
{/* Backdrop met CSS transition */}
<Animated.View
pointerEvents={isOpen ? 'auto' : 'none'}
style={{
...styles.backdrop,
opacity: isOpen ? 0.5 : 0,
transitionProperty: 'opacity',
transitionDuration: 250,
}}
/>
{/* Sheet met worklet-driven gesture */}
<GestureDetector gesture={pan}>
<Animated.View style={[styles.sheet, sheetStyle]}>
{children}
</Animated.View>
</GestureDetector>
</>
);
}
Dit voorbeeld vat de kracht van Reanimated 4 mooi samen: declaratieve CSS voor de backdrop fade, gesture-aware worklets voor de sheet zelf, en alles netjes op de UI thread.
Veelvoorkomende problemen oplossen
"Property 'value' doesn't exist"
Een klassieker. Je vergeet .value bij een shared value. Onthoud: sv is het object, sv.value is de waarde.
Animaties stotteren op Android
Check of je app daadwerkelijk op Hermes draait en of de Nieuwe Architectuur is ingeschakeld. Bouw een release-versie (eas build --profile production) — debug-builds zijn nu eenmaal langzamer, en dat geeft een vertekend beeld.
"useAnimatedStyle is being executed on the JavaScript thread"
Een worklet probeert een React state-functie aan te roepen zonder scheduleOnRN. Wikkel de aanroep correct:
import { scheduleOnRN } from 'react-native-worklets';
const tap = Gesture.Tap().onEnd(() => {
scheduleOnRN(setCount, count + 1);
});
FAQ
Werkt Reanimated 4 met de oude (Paper) architectuur?
Nee. Reanimated 4 ondersteunt uitsluitend de Nieuwe Architectuur (Fabric en bridgeless). Zit je nog op Paper, blijf dan bij Reanimated 3.x of plan een migratie naar React Native 0.76 of nieuwer.
Moet ik mijn bestaande Reanimated 3 code volledig herschrijven?
Niet nodig. Worklet-API's zoals useSharedValue, useAnimatedStyle, withTiming, withSpring, withSequence en layout-animaties werken ongewijzigd in v4. Je hoeft alleen de Babel-plugin aan te passen, de drempelparameters van withSpring te updaten en optioneel hernoemde functies te vervangen.
Wat is het verschil tussen CSS animaties en worklets in Reanimated 4?
CSS animaties zijn declaratief en ideaal voor state-gestuurde transities (modals, accordions, hover-effecten). Worklets zijn imperatief en geschikt voor gesture- en scroll-gestuurde interacties waar je frame-niveau controle nodig hebt. Beide draaien op de UI thread en kunnen prima in dezelfde component gecombineerd worden.
Werkt Reanimated 4 in Expo Go?
Ja, vanaf Expo SDK 54 zit Reanimated 4 ingebouwd in Expo Go. Voor productie raad ik aan een development build te gebruiken (npx expo install expo-dev-client) zodat je consistent gedrag krijgt met je release-build.
Hoe debug ik animatieproblemen in Reanimated 4?
Gebruik de nieuwe React Native DevTools (Chrome-gebaseerd) voor JavaScript-zijde inspectie. Voor UI-thread issues schakel je configureReanimatedLogger in om gedetailleerde worklet-logs te zien. De Performance Monitor in dev-mode toont frame drops; targets onder 60 FPS duiden meestal op te zwaar werk in een worklet of een ontbrekende useDerivedValue optimalisatie.
Conclusie
Reanimated 4 is geen refactor — het is een echte sprong vooruit. De CSS API verlaagt de drempel voor eenvoudige animaties drastisch, terwijl de bestaande worklet-API onaangetast blijft voor complexe interacties. Door de splitsing van worklets in een eigen package opent zich een ecosysteem waar ook andere libraries (denk aan react-native-skia en react-native-audio-api) UI-thread logica kunnen uitvoeren. Combineer dat met de exclusieve Nieuwe Architectuur ondersteuning en je hebt het meest performante animatie-framework dat React Native ooit heeft gehad.
Mijn tip? Begin klein. Pak één bestaand component met een state-gestuurde animatie en herschrijf het naar de CSS API. Vanaf daar groeit je vertrouwen vanzelf — en voor je het weet, verspreidt v4 zich vanzelf door je hele codebase.