![]()
Hãy mở ứng dụng Tiktok hoặc Facebook trên điện thoại của bạn lên và thử vuốt, chạm. Bạn sẽ thấy mọi thứ không hề xuất hiện và biến mất một cách thô cứng. Các nút bấm nảy lên khi chạm vào, các bức ảnh mờ dần rồi hiện rõ (fade-in), và các danh sách trượt theo ngón tay một cách hoàn hảo.
Đó chính là sức mạnh của Animation (Hiệu ứng chuyển động). Nó tạo ra "linh hồn" cho ứng dụng, giúp người dùng có cảm giác ứng dụng phản hồi nhanh và mượt mà hơn thực tế.
Trong React Native, có nhiều cách để làm Animation, nhưng hôm nay chúng ta sẽ bỏ qua những cách cũ kỹ để học thẳng công cụ tối thượng nhất, mạnh mẽ nhất hiện nay: React Native Reanimated 3.
1. Nỗi đau của hoạt ảnh truyền thống (Animated API)
React Native có sẵn một công cụ tên là Animated. Tuy nhiên, nếu bạn dùng nó để làm những hiệu ứng phức tạp, ứng dụng của bạn sẽ rất dễ bị giật lag (rớt khung hình - drop fps). Tại sao vậy?

Để hiểu điều này, bạn cần biết kiến trúc cốt lõi của điện thoại:
- JS Thread (Luồng tư duy): Nơi chứa code JavaScript của bạn. Nó lo việc gọi API, tính toán logic, quản lý State.
- UI Thread (Luồng tay chân): Nơi trực tiếp vẽ màu sắc, hình ảnh lên màn hình điện thoại.
Với cách làm cũ, mỗi khi một khung hình thay đổi (ví dụ nút bấm to ra 1 pixel), JS Thread phải tính toán rồi gửi "lệnh" sang cho UI Thread vẽ. Nó phải gửi đi gửi lại 60 lần trong 1 giây (60fps). Nếu lúc đó JS Thread đang bận rộn tính toán một cục dữ liệu lớn từ API, việc gửi lệnh sẽ bị tắc nghẽn ➔ Animation bị đứng hình!
Reanimated 3 ra đời để giải quyết bài toán này. Nó cho phép bạn gửi toàn bộ "kịch bản chuyển động" sang thẳng UI Thread. UI Thread sẽ tự động thực thi mượt mà ở mức 60-120fps mà không cần hỏi han gì JS Thread nữa, mặc kệ JS Thread có đang bị treo hay không!
2. Cài đặt Reanimated 3 trong Expo
Với Expo, việc cài đặt thư viện này cực kỳ đơn giản. Hãy mở Terminal và chạy lệnh:
npx expo install react-native-reanimated

⚠️ BƯỚC BẮT BUỘC: Sau khi cài xong, bạn phải mở file babel.config.js ở thư mục gốc của dự án và thêm plugin của Reanimated vào phần cuối cùng. File của bạn sẽ trông giống thế này:
module.exports = function (api) {
api.cache(true)
return {
presets: ['babel-preset-expo'],
plugins: [
'react-native-reanimated/plugin', // PHẢI NẰM Ở CUỐI CÙNG!
],
}
}
Sau đó, hãy khởi động lại server bằng lệnh npx expo start -c (thêm chữ -c để xóa bộ nhớ đệm).
3. Các công cụ mạnh mẽ nhất của Reanimated 3
Để tạo ra bất kỳ chuyển động nào, bạn chỉ cần nhớ đúng 3 bộ công cụ (Hooks) này:
Khái niệm 1: useSharedValue
(Biến trạng thái tàng hình)
Giống như useState, nhưng useSharedValue được thiết kế đặc biệt để lưu trữ các con số (như độ mờ, kích thước, tọa độ) mà không làm màn hình bị re-render mỗi khi giá trị thay đổi. Dữ liệu này được chia sẻ trực tiếp sang UI Thread.
Khái niệm 2: useAnimatedStyle
(Sợi dây kết nối)
Biến useSharedValue chỉ là một con số vô tri. Bạn cần dùng useAnimatedStyle để nói cho thẻ View biết: "Này thẻ View, hãy lấy con số này làm chiều rộng (width) của bạn nhé!".
Khái niệm 3: withTiming, withSpring
(Các hàm chuyển động)
Thay vì thay đổi giá trị đột ngột từ 1 thành 100, các hàm này giúp con số chạy từ 1 đến 100 một cách từ từ, tạo ra hiệu ứng chuyển động.
withTiming: Chuyển động đều đều theo thời gian (giống CSS Transition).withSpring: Chuyển động có độ nảy như lò xo (Rất được ưa chuộng trong Mobile UI).
4. Thực hành: Nút bấm "nảy lò xo" cực mượt
Hãy tạo một nút bấm "Xác nhận" thật sinh động. Khi người dùng bấm vào, nút sẽ lõm xuống một chút, và khi thả tay ra, nó sẽ nảy bật lên như một chiếc lò xo.
import React from 'react'
import { View, Text, Pressable, StyleSheet } from 'react-native'
// 1. Import các công cụ từ thư viện reanimated (Lưu ý: Phải có chữ Animated)
import Animated, { useSharedValue, useAnimatedStyle, withSpring } from 'react-native-reanimated'
export default function BounceButton() {
// 2. Khởi tạo giá trị mặc định cho độ phóng to/thu nhỏ (Scale). 1 có nghĩa là 100% kích thước gốc.
const scale = useSharedValue(1)
// 3. Kết nối giá trị scale vào thuộc tính transform của CSS
const animatedStyle = useAnimatedStyle(() => {
return {
transform: [{ scale: scale.value }],
}
})
// 4. Xử lý khi bắt đầu nhấn ngón tay vào
const handlePressIn = () => {
// Thu nhỏ lại còn 90% (0.9) với hiệu ứng lò xo
scale.value = withSpring(0.9)
}
// 5. Xử lý khi nhấc ngón tay ra
const handlePressOut = () => {
// Nảy trở lại 100% (1) kích thước gốc
scale.value = withSpring(1)
}
return (
<View style={styles.container}>
{/* 6. BẮT BUỘC: Sử dụng thẻ Animated.View thay vì View thường */}
<Animated.View style={[styles.buttonWrapper, animatedStyle]}>
{/* Dùng Pressable để bắt sự kiện In/Out chính xác nhất */}
<Pressable onPressIn={handlePressIn} onPressOut={handlePressOut} style={styles.button}>
<Text style={styles.text}>Bấm Vào Tôi!</Text>
</Pressable>
</Animated.View>
</View>
)
}
const styles = StyleSheet.create({
container: { flex: 1, justifyContent: 'center', alignItems: 'center' },
buttonWrapper: {
// Khung bọc bên ngoài sẽ chịu trách nhiệm chuyển động
},
button: {
backgroundColor: '#0984e3',
paddingVertical: 15,
paddingHorizontal: 40,
borderRadius: 30,
elevation: 5, // Bóng đổ Android
shadowColor: '#000', // Bóng đổ iOS
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.3,
},
text: { color: 'white', fontSize: 18, fontWeight: 'bold' },
})
Chỉ với vài dòng code ngắn gọn, bạn đã tạo ra một tương tác vật lý cực kỳ thỏa mãn mà không hề gây gánh nặng cho bộ vi xử lý!
5. Hiệu ứng xuất hiện tự động (Entering Animation)
Đôi khi, bạn muốn một danh sách các phần tử tự động mờ dần và trượt từ dưới lên khi màn hình vừa mở ra (giống như các thẻ bài lật mở). Reanimated 3 cung cấp một bộ Layout Animations có sẵn, giúp bạn làm điều này chỉ với 1 dòng code duy nhất!

import Animated, { FadeInUp } from 'react-native-reanimated'
export default function CardItem() {
return (
// Sử dụng thuộc tính entering và truyền hiệu ứng FadeInUp vào
// Thêm duration để chỉnh thời gian chậm lại một chút
<Animated.View entering={FadeInUp.duration(500).springify()} style={styles.card}>
<Text>Nội dung thẻ</Text>
</Animated.View>
)
}
Không cần tính toán useSharedValue phức tạp, Reanimated sẽ tự động lo liệu mọi phép toán ở dưới nền khi component được render lên màn hình.
Kết luận: Tạm biệt giật lag, chào đón sự mượt mà
Sử dụng Reanimated 3 là dấu hiệu nhận biết của một lập trình viên React Native Senior:
- Luôn dùng
Animated.View,Animated.Textđể bọc các phần tử muốn chuyển động. - Dùng
useSharedValueđể lưu thông số thay chouseState. - Dùng
useAnimatedStyleđể biến thông số thành style thực tế. - Tận dụng
withSpringđể tạo cảm giác tự nhiên, chân thực cho người dùng.
Trong bài viết này, chúng ta mới chỉ chạm vào bề nổi của các hiệu ứng tự động. Làm thế nào để người dùng có thể chạm ngón tay vào màn hình, vuốt và kéo thẻ View đi khắp nơi (giống ứng dụng hẹn hò Tinder)?
Hãy đón chờ những kiến thức bổ ích ở các bài viết tiếp theo nhé!