Command Palette

Search for a command to run...

Event Handling trong React Native: Sự khác biệt giữa Pressable và TouchableOpacity

Event Handling trong React Native

Ở bài trước, chúng ta đã trở thành những "kiến trúc sư" thực thụ khi sử dụng Flexbox để dàn trang và StyleSheet để làm đẹp cho ứng dụng. Tuy nhiên, dù giao diện của bạn có lộng lẫy đến đâu, nó vẫn chỉ là một bức tranh tĩnh nếu người dùng chạm vào mà không có chuyện gì xảy ra.

Trong bài này, chúng ta sẽ biến ứng dụng thành một thực thể "sống", biết lắng nghe và phản hồi lại mọi thao tác vuốt, chạm của người dùng. Hãy cùng khám phá cách xử lý sự kiện (Event Handling) trong React Native!

1. Sự thật bất ngờ về thẻ Button trong React Native

Nếu bạn đã từng lập trình Web, phản xạ đầu tiên của bạn khi muốn tạo một nút bấm là tìm đến thẻ <button>. React Native cũng cung cấp một Core Component tên là <Button>.

Tuy nhiên, có một sự thật phũ phàng: Các lập trình viên chuyên nghiệp hiếm khi dùng nó.

Tại sao vậy? Vì thẻ <Button> gốc của React Native rất cứng nhắc. Bạn không thể thêm thuộc tính style cho nó. Bạn không thể đổi font chữ, không thể bo góc, và tệ nhất là: Giao diện của nó trên iOS và Android trông hoàn toàn khác nhau!

Để có một nút bấm đẹp mắt, đồng nhất trên mọi thiết bị và có thể tùy biến 100% bằng Flexbox, chúng ta phải sử dụng nhóm component mang họ Touchable hoặc thế hệ mới nhất là Pressable.

2. Kỷ nguyên của Touchable: TouchableOpacity

Đây là "người hùng" được sử dụng nhiều nhất để tạo nút bấm trong suốt chiều dài lịch sử của React Native.

Đúng như tên gọi của nó (Opacity = Độ mờ), khi người dùng chạm vào thẻ này, toàn bộ nội dung bên trong sẽ hơi mờ đi một chút, tạo ra một hiệu ứng phản hồi thị giác cực kỳ tự nhiên và quen thuộc trên điện thoại.

Cách biến mọi thứ thành nút bấm

Bạn có thể bọc TouchableOpacity bên ngoài một đoạn Text, một bức ảnh, hoặc cả một khối View khổng lồ.

Hãy lấy ví dụ về việc xây dựng giao diện cho một ứng dụng cẩm nang chiến thuật. Khi người dùng muốn chốt một đội hình phối hợp chuẩn xác (đảm bảo tính tương thích về vai trò đi đường, chẳng hạn như kết hợp Đường Giữa và Đi Rừng), họ sẽ nhấn vào một nút xác nhận.

import React, { useState } from 'react'
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native'

export default function SynergySelector() {
  const [selectedSynergy, setSelectedSynergy] = useState('Chưa có đội hình nào được chọn')

  const handleSelectDuo = () => {
    // Cập nhật state khi nút được nhấn.
    // Ở đây ta chọn một cặp Mid - Rừng chuẩn mực.
    setSelectedSynergy('Katarina (Mid) & Amumu (Rừng)')
  }

  return (
    <View style={styles.container}>
      <Text style={styles.statusText}>Đang chọn: {selectedSynergy}</Text>

      {/* Nút bấm tự thiết kế với TouchableOpacity */}
      <TouchableOpacity
        style={styles.button}
        onPress={handleSelectDuo} // Bắt sự kiện nhấn
        activeOpacity={0.7} // Tùy chỉnh độ mờ khi nhấn (mặc định  0.2)
      >
        <Text style={styles.buttonText}>Xác Nhận Đội Hình</Text>
      </TouchableOpacity>
    </View>
  )
}

const styles = StyleSheet.create({
  container: { flex: 1, justifyContent: 'center', alignItems: 'center' },
  statusText: { fontSize: 18, marginBottom: 20, color: '#333' },
  button: {
    backgroundColor: '#0984e3',
    paddingVertical: 12,
    paddingHorizontal: 30,
    borderRadius: 8,
    elevation: 3, // Tạo bóng đổ trên Android
    shadowColor: '#000', // Tạo bóng đổ trên iOS
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.2,
  },
  buttonText: { color: 'white', fontSize: 16, fontWeight: 'bold' },
})

(Lưu ý: Nếu bạn sử dụng TouchableWithoutFeedback, nút bấm sẽ nhận sự kiện nhưng không có bất kỳ hiệu ứng mờ hay đổi màu nào. Nó thường được dùng cho các thao tác ẩn, ví dụ: Chạm vào khoảng không bên ngoài để ẩn bàn phím đi).

3. Tương lai của tương tác: Component Pressable

Mặc dù TouchableOpacity rất tốt, nhưng khi ứng dụng ngày càng phức tạp, đôi khi bạn muốn hiệu ứng nút bấm phong phú hơn là chỉ việc "làm mờ". Ví dụ: Bạn muốn nút bấm đổi sang màu đỏ khi giữ chặt, và chuyển lại màu xanh khi thả tay ra.

Đó là lý do React Native cho ra mắt Pressable. Đây là component hiện đại nhất, linh hoạt nhất và được khuyên dùng để thay thế toàn bộ họ nhà Touchable trong các dự án mới.

Sức mạnh của trạng thái pressed

Điểm "ăn tiền" nhất của Pressable là nó cho phép bạn truyền một hàm vào thuộc tính style để theo dõi xem nút có đang bị nhấn hay không.

import React from 'react'
import { Pressable, Text, StyleSheet, View } from 'react-native'

export default function ModernButton() {
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Pressable
        onPress={() => console.log('Đã nhấn!')}
        style={({ pressed }) => [
          styles.baseButton,
          // Nếu đang bị nhấn (pressed = true), đổi nền sang màu xám đen
          pressed ? { backgroundColor: '#2d3436' } : { backgroundColor: '#00b894' },
        ]}
      >
        {({ pressed }) => <Text style={styles.text}>{pressed ? 'Đang giữ chặt...' : 'Chạm vào tôi!'}</Text>}
      </Pressable>
    </View>
  )
}

const styles = StyleSheet.create({
  baseButton: {
    padding: 15,
    borderRadius: 10,
    minWidth: 150,
    alignItems: 'center',
  },
  text: { color: 'white', fontWeight: 'bold' },
})

Với Pressable, bạn làm chủ 100% cảm giác tương tác mà không cần phải viết những dòng code phức tạp để theo dõi animation.

4. Các loại sự kiện chạm mở rộng

Cả TouchableOpacityPressable đều hỗ trợ nhiều mốc sự kiện hơn là chỉ một cú chạm (onPress). Bạn có thể tận dụng chúng để tạo ra các tính năng nâng cao:

  • onPress: Kích hoạt khi người dùng chạm và thả tay ra (Hành động click phổ biến nhất).
  • onLongPress: Kích hoạt khi người dùng nhấn và giữ nút trong khoảng thời gian đủ lâu (khoảng 500ms). Thường dùng để mở menu phụ hoặc xóa một mục.
  • onPressIn: Kích hoạt ngay khoảnh khắc ngón tay vừa chạm vào màn hình (trước cả khi thả tay).
  • onPressOut: Kích hoạt khoảnh khắc ngón tay rời khỏi màn hình.

Mẹo nâng cao: Pressable còn có thuộc tính hitSlop. Nếu bạn có một nút bấm nhỏ (như nút X để tắt popup), bạn có thể dùng hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }} để mở rộng vùng có thể chạm, giúp người dùng ngón tay to dễ dàng bấm trúng hơn mà không làm thay đổi kích thước thực sự của nút bấm trên giao diện.

Kết luận: Ứng dụng giờ đã có sự tương tác

Để ứng dụng React Native phản hồi tương tác mượt mà:

  1. Tránh dùng <Button> mặc định nếu bạn muốn một giao diện có tính thẩm mỹ và đồng nhất cao.
  2. Dùng TouchableOpacity cho các trường hợp làm nút bấm nhanh, cần hiệu ứng mờ đơn giản.
  3. Chuyển sang sử dụng Pressable cho các dự án mới hoặc khi bạn cần tùy biến sâu trạng thái hiển thị lúc bấm, cũng như tận dụng hitSlop để tối ưu trải nghiệm (UX).

Đến đây, bạn đã biết cách vẽ giao diện và làm cho chúng "biết lắng nghe". Nhưng ứng dụng thực tế thường chứa hàng trăm, hàng ngàn mục dữ liệu (như bảng tin Facebook hay danh sách hàng hóa). Nếu bạn hiển thị tất cả chúng cùng lúc, điện thoại sẽ lập tức bị đơ!

Để giải quyết bài toán hóc búa này, chúng ta sẽ bước sang những bài học tiếp theo.

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à.

Hướng dẫn cài đặt môi trường React Native & Expo trong 15 phút

Bạn sợ cài đặt môi trường lập trình mobile phức tạp? Hướng dẫn chi tiết cách dùng Expo Go, Node.js để chạy app React Native ngay lập tức.

Stack Navigation trong Expo Router: Chuyển trang & Truyền tham số

Hướng dẫn chi tiết cách chuyển trang và truyền tham số bằng Stack Navigation trong React Native, sử dụng Expo Router.