react-native-reanimated 4
Reanimated 4 é o motor de animação padrão no Expo SDK 57. Valores compartilhados, useAnimatedStyle e helpers de timing/spring rodam na thread de UI para que gestos e scroll não travem quando o JavaScript está ocupado.
Busque em todas as páginas da documentação
Reanimated 4 é o motor de animação padrão no Expo SDK 57. Valores compartilhados, useAnimatedStyle e helpers de timing/spring rodam na thread de UI para que gestos e scroll não travem quando o JavaScript está ocupado.
Cartão de receita de referência rápida - pronto para copiar e colar.
npx expo install react-native-reanimated react-native-gesture-handler// babel.config.js - o plugin DEVE ser o último
module.exports = function (api) {
api.cache(true);
return {
presets: ["babel-preset-expo"],
plugins: ["react-native-reanimated/plugin"],
};
};import { StyleSheet, Text } from "react-native";
import Animated, {
useAnimatedStyle,
useSharedValue,
withSpring,
withTiming,
} from "react-native-reanimated";
export function ReanimatedCard() {
const scale = useSharedValue(1);
const opacity = useSharedValue(0);
const animatedStyle = useAnimatedStyle(() => ({
opacity: opacity.value,
transform: [{ scale: scale.value }],
}));
const reveal = () => {
opacity.value = withTiming(1, { duration: 250 });
scale.value = withSpring(1, { damping: 14 });
};
return (
<Animated.View style={[styles.card, animatedStyle]}>
<Text onPress={reveal}>Toque para revelar</Text>
</Animated.View>
);
}
const styles = StyleSheet.create({
card: { padding: 20, borderRadius: 12, backgroundColor: "#f0fdf4" },
});Quando usar isso:
width, borderRadius, backgroundColor)Um cartão arrastável que volta ao lugar ao soltar - valor compartilhado na thread de UI, spring ao final.
npx expo install react-native-reanimated react-native-gesture-handler// components/draggable-card.tsx
import { StyleSheet, Text } from "react-native";
import { Gesture, GestureDetector } from "react-native-gesture-handler";
import Animated, {
useAnimatedStyle,
useSharedValue,
withSpring,
} from "react-native-reanimated";
const SNAP_BACK = { damping: 18, stiffness: 220 };
export function DraggableCard({ title }: { title: string }) {
const translateX = useSharedValue(0);
const translateY = useSharedValue(0);
const pan = Gesture.Pan()
.onUpdate((e) => {
translateX.value = e.translationX;
translateY.value = e.translationY;
})
.onEnd(() => {
translateX.value = withSpring(0, SNAP_BACK);
translateY.value = withSpring(0, SNAP_BACK);
});
const style = useAnimatedStyle(() => ({
transform: [
{ translateX: translateX.value },
{ translateY: translateY.value },
],
}));
return (
<GestureDetector gesture={pan}>
<Animated.View style={[styles.card, style]}>
<Text>{title}</Text>
</Animated.View>
</GestureDetector>
);
}
const styles = StyleSheet.create({
card: {
padding: 20,
borderRadius: 16,
backgroundColor: "#fff",
shadowColor: "#000",
shadowOpacity: 0.08,
shadowRadius: 8,
elevation: 3,
},
});// app/_layout.tsx (excerto)
import { GestureHandlerRootView } from "react-native-gesture-handler";
export default function RootLayout() {
return (
<GestureHandlerRootView style={{ flex: 1 }}>
{/* Stack / provedores */}
</GestureHandlerRootView>
);
}// Helper de timing - barra de progresso controlada por valor compartilhado
import Animated, {
Easing,
useAnimatedStyle,
useSharedValue,
withTiming,
} from "react-native-reanimated";
export function useProgressBar(progress: number) {
const width = useSharedValue(0);
width.value = withTiming(progress, {
duration: 400,
easing: Easing.out(Easing.cubic),
});
return useAnimatedStyle(() => ({
width: `${width.value * 100}%`,
}));
}useSharedValue(inicial) aloca um slot mutável legível e gravável a partir de worklets. Atribua com .value:
const offset = useSharedValue(0);
offset.value = 42; // imediato
offset.value = withTiming(1); // transição animadauseAnimatedStyle, useDerivedValue, ou callbacks de gesto marcados como worklets.useDerivedValue.Retorna um objeto de estilo cujos getters são re-executados na thread de UI a cada frame:
const style = useAnimatedStyle(() => ({
opacity: interpolate(progress.value, [0, 1], [0.4, 1]),
transform: [{ translateX: offset.value }],
}));'worklet'.entering / exiting (veja Layout Animations).| Helper | Melhor para | Opções chave |
|---|---|---|
withTiming | Fades, durações precisas, barras de progresso | duration, easing |
withSpring | Arrastos, chips, pontos de snap de folha inferior | damping, stiffness, mass |
opacity.value = withTiming(1, { duration: 200 });
translateY.value = withSpring(0, { damping: 15, stiffness: 120 });withDelay, withRepeat e withSequence para movimento em etapas.Worklets não podem chamar JS arbitrário (navegação, setState, analytics). Use runOnJS:
import { runOnJS } from "react-native-reanimated";
const pan = Gesture.Pan().onEnd((e) => {
if (e.translationX < -120) {
runOnJS(onDismiss)();
}
});runOnJS agenda na thread JS no próximo tick - não o use a cada frame em onUpdate.npx expo install, não com palpites do npm.Plugin Babel não é o último - Worklets falham na transformação; animações travam na thread JS. Correção: Mova react-native-reanimated/plugin para o final de plugins e rode npx expo start --clear.
Importando Animated de react-native - Misturar Animated clássico com estilos de worklet causa erros de tipo e de tempo de execução. Correção: import Animated from 'react-native-reanimated' para componentes worklet.
Lendo valores compartilhados no render do React - translateX.value no corpo JSX não se inscreve em atualizações. Correção: Leia apenas dentro de useAnimatedStyle ou useDerivedValue; use useAnimatedProps para props nativas.
Chamando setState dentro de useAnimatedStyle - Dispara erros "Tried to synchronously call a function on a non-worklet thread". Correção: runOnJS(setState) apenas em handlers de fim de gesto.
Esquecendo GestureHandlerRootView - Gestos nunca disparam; arrastos parecem congelados. Correção: Envolva o layout raiz (veja react-native-gesture-handler).
Animando width como strings percentuais incorretamente - Algumas versões do RN coerem de forma estranha. Correção: Anime width numérico a partir de medição onLayout ou use flex + scaleX para barras simples.
Trabalho pesado em onUpdate - Parsing de JSON ou logging a cada frame de pan derruba frames. Correção: Mantenha onUpdate para matemática de valor compartilhado; adie o trabalho para onEnd via runOnJS.
| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
API Animated | Fades de tiro único em telas estáticas | Arrastos seguindo o dedo ou acoplamento com scroll de lista |
| Reanimated 4 | Gestos, layout, UI interativa a 60fps | Fade de opacidade trivial de 200ms sem gesto |
react-native-animatable | Animações declarativas de classe estilo CSS | Física personalizada ligada a gestos |
Lottie (lottie-react-native) | Loops vetoriais criados por designers | Componentes arrastáveis interativos |
| Transições CSS (apenas Expo web) | Superfícies apenas para web | Alvos de envio nativos iOS/Android |
npx expo install react-native-reanimated react-native-gesture-handlerVerifique se babel.config.js inclui react-native-reanimated/plugin como o último plugin. Reinicie o Metro com --clear após a instalação.
useSharedValue - Slot na thread de UI; sem re-renderização do React na mudança; lido em worklets.useState - Estado do React na thread JS; dispara renderização; nunca atualize a cada frame de animação.withTiming quando o design especifica duração exata (modais, progresso, cross-fades).withSpring quando o movimento deve parecer físico (arrastos, snap-back, toggles saltitantes).Sim para animações de montagem, transições de layout e timing acionado por clique. Qualquer cenário de conflito de pan/pinch ou scroll deve adicionar Gesture Handler.
configureReanimatedLogger (veja Worklets & Bundle Mode).Projetos do SDK 57 rodam cada vez mais a Nova Arquitetura por padrão. Reanimated 4 visa essa stack; a arquitetura mais antiga pode ainda funcionar, mas o suporte da equipe foca em Fabric + Hermes.
Use interpolateColor dentro de useAnimatedStyle:
backgroundColor: interpolateColor(progress.value, [0, 1], ["#ef4444", "#22c55e"])Animated vs ReanimatedGesture.Pan e gestos compostosFadeIn, Layout, reordenação de listasVersões da Stack: Esta página foi escrita para React 19.2.3, React Native 0.86.0, e Expo SDK 57 (
expo~57.0.4).
Revisado por Chris St. John·Última atualização: 16 de jul. de 2026