Command Palette

Search for a command to run...

Animation trong React Native: Hướng dẫn toàn tập Reanimated 3

Animation trong React Native

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?

React Native Animated API

Để 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

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!

Transition Animation trong React Native

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:

  1. Luôn dùng Animated.View, Animated.Text để bọc các phần tử muốn chuyển động.
  2. Dùng useSharedValue để lưu thông số thay cho useState.
  3. Dùng useAnimatedStyle để biến thông số thành style thực tế.
  4. 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é!

Bài viết liên quan

Cách gọi API trong React Native: Hướng dẫn Fetch Data và xử lý JSON

Hướng dẫn chi tiết cách gọi API trong React Native. Nắm vững kỹ thuật sử dụng fetch, axios kết hợp với useEffect, useState để tải và hiển thị dữ liệu server mượt mà.

Cách dùng FlatList trong React Native: Hiển thị danh sách không giật lag

Giải quyết bài toán hiển thị danh sách dữ liệu lớn với FlatList và SectionList. Hướng dẫn tối ưu hóa bộ nhớ và tốc độ cuộn (scroll) mượt mà.

Quản lý Global State trong React Native: Redux Toolkit hay Zustand?

Giải thích chi tiết khái niệm Global State và Prop Drilling. Hướng dẫn cách cài đặt, sử dụng Redux Toolkit và Zustand để quản lý luồng dữ liệu React Native.

Hướng dẫn cách dùng React Native Maps: Hiển thị bản đồ & Lấy tọa độ GPS

Hướng dẫn hiển thị bản đồ trong React Native bằng thư viện react-native-maps. Tìm hiểu cách ghim vị trí (Marker) và tích hợp GPS theo thời gian thực.