Thú thật, tôi đã chần chừ hai tháng trước khi migrate một app production thật sự sang Reanimated 4. Lý do? Bản 3.15 vẫn chạy ổn, và nỗi sợ "bản major lớn luôn có vài bug đầu tiên" cũng có thật. Nhưng sau khi ngồi xem buổi talk của đội Software Mansion ở App.js Conf đầu 2026 và thử rewrite một màn hình swipe-to-delete, tôi hiểu ra: đây không phải là một bản cập nhật, mà là lần viết lại nền tảng animation của React Native.
Reanimated 4 là bản phát hành lớn nhất của thư viện animation số một trong hệ sinh thái React Native kể từ khi khái niệm worklet ra đời ở Reanimated 2. Với bản stable ra mắt đầu năm 2026, thư viện này đã bỏ hoàn toàn Legacy Architecture, giới thiệu API CSS Animations và Transitions khai báo quen thuộc với developer web, đồng thời tách worklet ra một package riêng (react-native-worklets) để phục vụ các thư viện khác như Skia hay Audio API. Nếu app của bạn vẫn chạy React Native 0.83/0.84 với Hermes V1 và New Architecture mặc định, đây chính là thời điểm để nâng cấp.
Ok, vào việc luôn. Hướng dẫn này đi từ cài đặt, khái niệm lõi, cho tới các pattern gesture phức tạp thật sự xuất hiện trong sản phẩm: drag-and-drop, bottom sheet, parallax header, swipe-to-delete. Tất cả ví dụ đều chạy trên New Architecture của React Native 0.83+, có đầy đủ TypeScript, và tuân theo khuyến nghị từ đội Software Mansion năm 2026.
Có gì mới trong Reanimated 4 (so với 3.x)
Reanimated 4 không chỉ là một bản cập nhật thông thường. Đây là lần viết lại bộ lõi lớn nhất của thư viện, với mục tiêu hợp nhất mô hình mental model giữa React Native và Web:
- CSS Animations API — bạn có thể dùng cú pháp
animationName,animationDuration,animationTimingFunction, cùng keyframes khai báo, y hệt CSS web. Đây là tính năng highlight của 4.0. - CSS Transitions API — chỉ cần set
transitionPropertyvàtransitionDuration, Reanimated tự nội suy khi style thay đổi. Không cần shared value, không cầnuseAnimatedStylenữa cho các animation cơ bản. - Worklets tách package — runtime worklet giờ nằm ở
react-native-worklets, cho phép các thư viện khác (Skia, Audio, Sensors) dùng chung hạ tầng. Thay đổi này nghe có vẻ nhỏ, nhưng ảnh hưởng rất lớn tới cả hệ sinh thái. - Bỏ Legacy Architecture — Reanimated 4.x chỉ chạy trên New Architecture (bắt buộc từ RN 0.76+, đã là mặc định từ 0.76 và bỏ bridge cũ ở 0.82).
- Bỏ
useAnimatedGestureHandler— API này đã deprecated từ Reanimated 3 và bị xóa hẳn ở 4. Bạn phải migrate sang Gesture API mới củareact-native-gesture-handlerv3. - Worklet serialization hiệu quả hơn — overhead khi gửi worklet function sang native runtime giảm đáng kể, quan trọng với những app có nhiều component animated được mount/unmount liên tục.
- Tương thích ngược với v2/v3 API — code dựa trên
useSharedValue+useAnimatedStylechạy như cũ, bạn có thể adopt CSS animations theo tiến độ, không cần rewrite toàn bộ. Đây là chi tiết tôi thấy quan trọng nhất, vì nó cho phép migrate từ từ thay vì phải đóng băng feature trong một sprint.
Khi nào nên dùng CSS, khi nào nên dùng worklets
Đây là câu hỏi đầu tiên mọi developer gặp khi tiếp xúc Reanimated 4. Khuyến nghị chính thức từ Software Mansion (và cũng trùng với kinh nghiệm của tôi sau vài tuần dùng):
- CSS Animations/Transitions — animation được kích hoạt bởi state (mount/unmount, toggle modal, thay đổi màu theme, fade-in card, loading spinner). Code khai báo, ít dòng, dễ đọc.
- Worklets + Shared Values — animation được điều khiển bởi gesture (drag, swipe, pinch), scroll (parallax, collapsing header, sticky), hoặc vật lý (spring chain, momentum). Những cảnh cần truy cập giá trị liên tục theo frame, không thể biểu diễn bằng keyframe.
Nói ngắn gọn: nếu animation của bạn có thể mô tả chỉ bằng "đi từ A đến B trong X ms", CSS là đủ. Còn nếu giá trị phụ thuộc vào ngón tay user hay vị trí scroll, bạn cần worklet.
Yêu cầu môi trường và cài đặt
Điều kiện tiên quyết
- React Native 0.76 trở lên (khuyến nghị 0.83+ với Hermes V1 mặc định).
- New Architecture bật (Fabric + TurboModules). Nếu dự án tạo bằng Expo SDK 53+ hay RN 0.76+, đây đã là mặc định.
- Hermes engine (Reanimated 4 không chính thức hỗ trợ JSC).
- Node 20+, Xcode 16+, Android Studio Meerkat trở lên.
Cài đặt cho Expo
npx expo install react-native-reanimated react-native-worklets react-native-gesture-handler
Expo SDK 55 tự động wire plugin worklet vào babel và Metro khi bạn chạy npx expo prebuild hoặc build qua EAS. Không cần chỉnh babel.config.js thủ công — và đây là một thay đổi nhỏ nhưng cực kỳ đáng giá, vì ở Reanimated 3 không ít team đã mất cả buổi chiều vì quên dòng plugin.
Cài đặt cho React Native CLI
npm install react-native-reanimated react-native-worklets react-native-gesture-handler
cd ios && pod install
Với dự án RN CLI, bạn phải tự thêm plugin worklet vào babel.config.js, và nó phải là plugin cuối cùng:
// babel.config.js
module.exports = {
presets: ['module:@react-native/babel-preset'],
plugins: [
'react-native-worklets/plugin', // BẮT BUỘC phải ở cuối cùng
],
};
Bọc ứng dụng bằng GestureHandlerRootView
Nếu dùng gesture, bắt buộc bọc root component bằng GestureHandlerRootView. Quên bước này là lỗi "gesture không phản hồi" phổ biến nhất năm 2026 — tôi đã debug hai giờ một lần vì chính lỗi này, nên cứ coi đây là checkpoint bắt buộc:
// App.tsx
import { GestureHandlerRootView } from 'react-native-gesture-handler';
export default function App() {
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<RootNavigator />
</GestureHandlerRootView>
);
}
CSS Animations API: cú pháp web quen thuộc
Đây là phần bạn sẽ dùng hàng ngày. CSS Animations trong Reanimated 4 hoạt động gần như giống web: bạn khai báo keyframes, gán vào style của Animated.View, animation tự chạy. Không useSharedValue, không withTiming, không hook nào cả.
Ví dụ 1: Fade-in + slide-up khi component mount
import Animated from 'react-native-reanimated';
import { StyleSheet, Text } from 'react-native';
export function WelcomeCard() {
return (
<Animated.View style={styles.card}>
<Text style={styles.title}>Xin chào React Native Relay</Text>
</Animated.View>
);
}
const styles = StyleSheet.create({
card: {
padding: 24,
backgroundColor: '#0ea5e9',
borderRadius: 16,
animationName: {
from: { opacity: 0, transform: [{ translateY: 24 }] },
to: { opacity: 1, transform: [{ translateY: 0 }] },
},
animationDuration: '450ms',
animationTimingFunction: 'ease-out',
animationFillMode: 'forwards',
},
title: { color: 'white', fontSize: 18, fontWeight: '600' },
});
So với Reanimated 3, bạn không cần useSharedValue, không cần useAnimatedStyle, không cần withTiming. CSS engine lo toàn bộ. Nếu bạn đến từ thế giới web, cảm giác sẽ y hệt việc đang viết một file SCSS.
Ví dụ 2: Animation lặp vô hạn (loading indicator)
const styles = StyleSheet.create({
spinner: {
width: 36,
height: 36,
borderRadius: 18,
borderWidth: 3,
borderColor: '#0ea5e9',
borderTopColor: 'transparent',
animationName: {
from: { transform: [{ rotate: '0deg' }] },
to: { transform: [{ rotate: '360deg' }] },
},
animationDuration: '900ms',
animationIterationCount: 'infinite',
animationTimingFunction: 'linear',
},
});
Ví dụ 3: Keyframes nhiều bước (bounce)
animationName: {
'0%': { transform: [{ translateY: 0 }] },
'40%': { transform: [{ translateY: -20 }] },
'60%': { transform: [{ translateY: -10 }] },
'100%': { transform: [{ translateY: 0 }] },
},
animationDuration: '700ms',
animationIterationCount: 3,
CSS Transitions API: chuyển đổi khi style thay đổi
Transitions phù hợp khi bạn muốn mượt hóa chuyển đổi state (ví dụ: isActive bật/tắt đổi màu). Chỉ cần khai báo property nào cần transition và thời lượng:
import { useState } from 'react';
import Animated from 'react-native-reanimated';
import { Pressable } from 'react-native';
export function ToggleChip() {
const [active, setActive] = useState(false);
return (
<Pressable onPress={() => setActive((v) => !v)}>
<Animated.View
style={{
paddingHorizontal: 16,
paddingVertical: 8,
borderRadius: 999,
backgroundColor: active ? '#0ea5e9' : '#e2e8f0',
transform: [{ scale: active ? 1.05 : 1 }],
transitionProperty: ['backgroundColor', 'transform'],
transitionDuration: '220ms',
transitionTimingFunction: 'ease-out',
}}
/>
</Pressable>
);
}
Reanimated tự động interpolate màu và transform mỗi khi state active thay đổi, không cần một dòng worklet nào. Thực sự, khi chuyển những toggle kiểu này sang transitions, số dòng code trong dự án của tôi giảm khoảng 30% — và đáng ngạc nhiên hơn là đọc dễ hơn nhiều.
Worklets và Shared Values: khi CSS không đủ
Với gesture và scroll, bạn cần giá trị cập nhật liên tục theo frame trên UI thread. Đây là địa hạt của worklets.
Shared Values — biến sống ở cả JS và UI thread
import { useSharedValue, useAnimatedStyle, withSpring } from 'react-native-reanimated';
import Animated from 'react-native-reanimated';
import { Pressable } from 'react-native';
export function TapScale() {
const scale = useSharedValue(1);
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ scale: scale.value }],
}));
return (
<Pressable
onPressIn={() => (scale.value = withSpring(0.92))}
onPressOut={() => (scale.value = withSpring(1))}
>
<Animated.View style={[styles.btn, animatedStyle]} />
</Pressable>
);
}
Quan trọng: bạn không bao giờ dùng setState cho animation values. Shared value là channel duy nhất truyền dữ liệu giữa JS và UI thread mà không tốn commit React. Tôi biết điều này nghe hiển nhiên, nhưng đây vẫn là sai lầm số một của developer mới tiếp xúc Reanimated.
Quy tắc viết worklet an toàn
- Đánh dấu function bằng
'worklet'trực tiếp ở dòng đầu, hoặc bọc trongrunOnUI. - Chỉ truy cập shared value hoặc primitive. Không gọi function JS thuần (dùng
runOnJSnếu cần). - Không import module toàn cục chưa worklet-hóa.
- Không dùng closure bắt state React, vì nó không sync sang UI thread.
Gestures với Gesture Handler v3
Reanimated 4 bỏ useAnimatedGestureHandler. Bạn bắt buộc dùng API mới Gesture.Pan(), Gesture.Pinch(), Gesture.Tap()... kết hợp với GestureDetector. Tin tốt là API mới ngắn hơn và dễ compose hơn nhiều.
Ví dụ: Draggable card
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
import Animated, { useSharedValue, useAnimatedStyle, withSpring } from 'react-native-reanimated';
import { StyleSheet } from 'react-native';
export function DraggableCard() {
const translateX = useSharedValue(0);
const translateY = useSharedValue(0);
const pan = Gesture.Pan()
.onChange((e) => {
translateX.value += e.changeX;
translateY.value += e.changeY;
})
.onEnd(() => {
translateX.value = withSpring(0);
translateY.value = withSpring(0);
});
const style = useAnimatedStyle(() => ({
transform: [
{ translateX: translateX.value },
{ translateY: translateY.value },
],
}));
return (
<GestureDetector gesture={pan}>
<Animated.View style={[styles.card, style]} />
</GestureDetector>
);
}
const styles = StyleSheet.create({
card: {
width: 160, height: 220, borderRadius: 20,
backgroundColor: '#0ea5e9', alignSelf: 'center', marginTop: 60,
},
});
Combine gesture: Pan + Pinch đồng thời
Một trong những cải thiện lớn của Gesture Handler v3 là simultaneous gesture handling nhất quán — pain point số một của production app dùng Reanimated 3:
const pan = Gesture.Pan().onChange(/* ... */);
const pinch = Gesture.Pinch().onChange((e) => {
scale.value *= e.scaleChange;
});
const composed = Gesture.Simultaneous(pan, pinch);
return (
<GestureDetector gesture={composed}>
<Animated.View style={[styles.photo, animatedStyle]} />
</GestureDetector>
);
Pattern thực tế 1: Swipe-to-delete row
Một list row có thể vuốt sang trái để lộ nút xóa. Snap về 0 hoặc về -88px khi thả. Cực kỳ phổ biến trong app messaging và todo.
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
import Animated, {
useSharedValue, useAnimatedStyle, withSpring,
} from 'react-native-reanimated';
const REVEAL = -88;
export function SwipeRow({ onDelete, children }: Props) {
const x = useSharedValue(0);
const pan = Gesture.Pan()
.activeOffsetX([-10, 10])
.onChange((e) => {
x.value = Math.min(0, x.value + e.changeX);
})
.onEnd((e) => {
if (x.value < REVEAL / 2 && e.velocityX < 0) {
x.value = withSpring(REVEAL);
} else {
x.value = withSpring(0);
}
});
const style = useAnimatedStyle(() => ({
transform: [{ translateX: x.value }],
}));
return (
<Animated.View>
<Animated.View style={styles.deleteBtn}>
<Pressable onPress={onDelete}><Text>Xóa</Text></Pressable>
</Animated.View>
<GestureDetector gesture={pan}>
<Animated.View style={[styles.row, style]}>{children}</Animated.View>
</GestureDetector>
</Animated.View>
);
}
activeOffsetX rất quan trọng để Pan không "ăn" gesture scroll dọc của FlashList bao ngoài. Thiếu nó, list của bạn sẽ cảm giác lag khi vuốt xuống — đây là một trong những lỗi khó reproduce nhất vì nó chỉ xuất hiện rõ trên thiết bị Android tầm trung.
Pattern thực tế 2: Collapsing header với scroll
Header co lại và mờ dần khi user scroll. Dùng useAnimatedScrollHandler để capture offset Y trên UI thread:
import Animated, {
useSharedValue, useAnimatedScrollHandler, useAnimatedStyle,
interpolate, Extrapolation,
} from 'react-native-reanimated';
const HEADER_MAX = 220;
const HEADER_MIN = 72;
export function ProfileScreen() {
const scrollY = useSharedValue(0);
const onScroll = useAnimatedScrollHandler({
onScroll: (e) => { scrollY.value = e.contentOffset.y; },
});
const headerStyle = useAnimatedStyle(() => ({
height: interpolate(
scrollY.value,
[0, HEADER_MAX - HEADER_MIN],
[HEADER_MAX, HEADER_MIN],
Extrapolation.CLAMP,
),
opacity: interpolate(
scrollY.value,
[0, (HEADER_MAX - HEADER_MIN) * 0.6],
[1, 0.2],
Extrapolation.CLAMP,
),
}));
return (
<>
<Animated.View style={[styles.header, headerStyle]} />
<Animated.ScrollView
onScroll={onScroll}
scrollEventThrottle={1}
contentContainerStyle={{ paddingTop: HEADER_MAX }}
>
{/* content */}
</Animated.ScrollView>
</>
);
}
Đặt scrollEventThrottle={1} là an toàn với Reanimated vì event không đi qua JS thread. Trên Paper cũ bạn phải set 16; giờ thì không cần lo nữa.
Pattern thực tế 3: Bottom sheet có snap points
Bottom sheet custom không dùng thư viện, để minh họa Pan + snap. (Bạn nên dùng @gorhom/bottom-sheet cho production, nhưng tự viết một lần là cách nhanh nhất để hiểu cơ chế.)
import { Dimensions } from 'react-native';
const { height } = Dimensions.get('window');
const SNAPS = [height * 0.9, height * 0.4, 80]; // closed, half, full
export function BottomSheet({ children }: { children: React.ReactNode }) {
const translateY = useSharedValue(SNAPS[0]);
const start = useSharedValue(0);
const pan = Gesture.Pan()
.onStart(() => { start.value = translateY.value; })
.onChange((e) => {
translateY.value = Math.max(SNAPS[2], start.value + e.translationY);
})
.onEnd((e) => {
const target = nearestSnap(translateY.value, e.velocityY);
translateY.value = withSpring(target, { damping: 18, stiffness: 180 });
});
const style = useAnimatedStyle(() => ({
transform: [{ translateY: translateY.value }],
}));
return (
<GestureDetector gesture={pan}>
<Animated.View style={[styles.sheet, style]}>{children}</Animated.View>
</GestureDetector>
);
}
function nearestSnap(y: number, velocity: number) {
'worklet';
const projected = y + velocity * 0.2;
return SNAPS.reduce((prev, curr) =>
Math.abs(curr - projected) < Math.abs(prev - projected) ? curr : prev
);
}
Lưu ý dòng 'worklet' trong nearestSnap: nó được gọi từ worklet onEnd, nên phải chạy trên UI thread. Quên dòng này thì ứng dụng sẽ crash với lỗi khó hiểu kiểu "function is not a worklet".
Migrate từ Reanimated 3.x lên 4.x
Checklist bắt buộc
- Đảm bảo app đã bật New Architecture (RN 0.76+). Nếu còn Paper, bạn không thể cài 4.x.
- Bỏ mọi import
useAnimatedGestureHandler. Chuyển sangGesture.Pan(),Gesture.Tap(),GestureDetector. - Cài thêm
react-native-worklets(không thể chỉ córeact-native-reanimated). - Thêm
react-native-worklets/pluginvàobabel.config.js(CLI) — plugin phải ở cuối. - Clean build: xóa
ios/build,android/build,node_modules, rebuild. - Kiểm tra
App.tsxcó bọcGestureHandlerRootViewchưa.
Chuyển useAnimatedGestureHandler cũ sang API mới
Trước (Reanimated 3):
const handler = useAnimatedGestureHandler({
onStart: (_, ctx) => { ctx.startX = x.value; },
onActive: (e, ctx) => { x.value = ctx.startX + e.translationX; },
onEnd: () => { x.value = withSpring(0); },
});
return <PanGestureHandler onGestureEvent={handler}>...</PanGestureHandler>;
Sau (Reanimated 4 + GH v3):
const startX = useSharedValue(0);
const pan = Gesture.Pan()
.onStart(() => { startX.value = x.value; })
.onChange((e) => { x.value = startX.value + e.translationX; })
.onEnd(() => { x.value = withSpring(0); });
return <GestureDetector gesture={pan}>...</GestureDetector>;
Không còn ctx — thay bằng shared value riêng để giữ trạng thái tạm thời. Thoạt nhìn thì có vẻ nhiều dòng hơn, nhưng thực ra rõ ràng hơn nhiều khi gesture bắt đầu phức tạp.
Tips hiệu năng cho Reanimated 4 trên New Architecture
- Dùng shared value thay vì state cho pressed/hover.
setStateép React re-render; shared value không. - Tránh
useAnimatedReactionquá nhiều. Mỗi reaction là một subscription UI thread; 50+ reactions có thể gây jitter trên Android tầm trung. - Batch update shared value trong cùng worklet. Mỗi write trigger một layout pass; nhóm chúng lại nếu có thể.
- Dùng
interpolatevớiExtrapolation.CLAMPthay vìMath.min/maxđể tránh nhánh điều kiện trong worklet. - Kết hợp FlashList 2 — FlatList truyền thống không đủ mượt cho animated list item; FlashList 2 có recycler tối ưu cho New Architecture.
- Bật Hermes V1 (mặc định RN 0.84+) — compile worklet nhanh hơn, khởi động app giảm 10-15%.
Sai lầm thường gặp và cách khắc phục
"Gesture không phản hồi trên Android"
99% là do thiếu GestureHandlerRootView ở root. Trên iOS bạn có thể không thấy vấn đề, nhưng Android thì bắt buộc. (Và vâng, tôi đã gặp chuyện này nhiều hơn tôi muốn thừa nhận.)
"Reanimated 4 doesn't support old Architecture"
Lỗi rõ ràng. Bạn phải bật newArchEnabled=true trong android/gradle.properties và RCT_NEW_ARCH_ENABLED=1 khi pod install. Với Expo, nếu dùng managed workflow qua EAS, thêm vào app.json:
{
"expo": {
"newArchEnabled": true
}
}
"Cannot read property 'value' of undefined" trong worklet
Worklet bắt closure của shared value, nhưng nếu shared value được tạo có điều kiện (trong if, hoặc useMemo phụ thuộc), nó có thể undefined lần render đầu. Luôn khởi tạo ở top-level component.
Animation giật khi debug bằng Chrome DevTools cũ
Remote JS Debugger (Chrome) không chạy được worklet. Với Reanimated 4, bắt buộc dùng React Native DevTools (debug dựa trên Hermes Inspector). Đây là debugger mặc định từ RN 0.76+.
"Cannot find module react-native-worklets/plugin"
Bạn cài thiếu package react-native-worklets. Khác Reanimated 3, giờ nó phải được cài rõ ràng, không tự có khi cài react-native-reanimated.
Reanimated 4 với Skia, Audio và hệ sinh thái worklets
Vì worklet runtime đã tách thành package chung, 2026 bắt đầu xuất hiện các thư viện khác xây trên hạ tầng này:
- React Native Skia — canvas 2D, shader, chart. Shader parameter có thể driven bởi shared value của Reanimated.
- React Native Audio API — xử lý audio sample-level trên worklet thread.
- Sensors worklets — gyroscope/accelerometer đẩy thẳng giá trị vào shared value, driven parallax bằng gyro mà không chạm JS thread.
Điều này có nghĩa khi chọn animation stack năm 2026, Reanimated 4 không chỉ là thư viện animation — nó là nền tảng UI thread mà các package khác cắm vào. Một cách nhìn khác: đầu tư hiểu worklet ngay bây giờ sẽ trả cổ tức rất lâu.
FAQ — Các câu hỏi thường gặp
Reanimated 4 có bắt buộc New Architecture không?
Có. 4.x chỉ chạy trên Fabric + TurboModules. Legacy (Paper) đã bị bỏ hoàn toàn. Nếu app của bạn chưa migrate New Architecture, giải pháp tạm là giữ Reanimated 3.x, còn về dài hạn bạn vẫn phải chuyển vì bridge cũ đã retire ở RN 0.82.
Tôi có nên rewrite toàn bộ animation sang CSS Animations không?
Không. Khuyến nghị chính thức là giữ worklet + shared value cho gesture, scroll, animation phức tạp orchestrate nhiều giá trị; và chỉ dùng CSS cho animation khai báo đơn giản kích hoạt bởi state (modal, fade, toggle). Hai API cùng tồn tại, interop tốt, có thể adopt theo tiến độ.
Sự khác biệt giữa Reanimated và React Native Animated API cũ?
Animated API cũ (core của RN) chạy animation qua native driver hoặc JS driver, có giới hạn lớn: không hỗ trợ layout animation phức tạp, không có worklet, không đọc được scroll offset mượt. Reanimated chạy trên UI thread, hỗ trợ worklet, shared value, gesture, layout animation — phù hợp cho app production. Khuyến nghị 2026: không dùng Animated API cũ cho dự án mới.
Tại sao useAnimatedGestureHandler bị xóa?
API này đã deprecated từ Reanimated 3 vì Gesture Handler v2 giới thiệu API mới Gesture.Pan() gom gesture và animation thành một chain duy nhất, giảm boilerplate, hỗ trợ compose (Simultaneous, Exclusive, Race) tốt hơn, và xử lý simultaneous gesture ổn định hơn. Giữ API cũ chỉ làm rối developer mới.
Reanimated 4 có hoạt động trên Expo Go không?
Có, nhưng chỉ nếu Expo SDK của bạn có bundle Reanimated cùng phiên bản (SDK 55 đã bundle 4.x). Với các native module custom khác ngoài Expo Go runtime, bạn phải chuyển sang development build qua EAS.
Làm sao để debug worklet?
Dùng console.log bên trong worklet — từ Reanimated 3 đã hỗ trợ proxy log sang JS thread. Với breakpoint, bạn cần React Native DevTools (Hermes Inspector). Remote Debug Chrome cũ không chạy worklet vì worklet yêu cầu JSI, không có khi JS chạy trong Chrome V8.
Kết luận
Reanimated 4 là một bước ngoặt: nó hợp nhất mô hình animation web và native, đưa CSS Animations vào React Native một cách nguyên bản, đồng thời củng cố worklet runtime thành nền tảng dùng chung cho Skia, Audio, Sensors. Với New Architecture đã là mặc định từ RN 0.76, Hermes V1 đã default từ 0.84, và bridge cũ đã retire, đây là thời điểm để toàn bộ dự án React Native mới chuẩn hóa trên stack Reanimated 4 + Gesture Handler v3 + FlashList 2.
Bắt đầu nhỏ: thay thế một animation mount/unmount sang CSS API, hoặc migrate một swipe-to-delete sang Gesture API mới. Bạn sẽ thấy code ngắn đi đáng kể, app mượt hơn trên Android tầm trung, và khi codebase scale, bạn vẫn còn worklet để xử lý những cảnh gesture phức tạp mà không thư viện web nào làm được. Lời khuyên cuối — đừng chờ. Càng sớm làm quen, càng đỡ phải refactor khi team bạn nhảy lên RN 0.85 sang năm.