Command Palette

Search for a command to run...

Ôn tập React Hooks: Cách hoạt động của chúng trong môi trường Mobile

React Hooks: Cách hoạt động trong môi trường Mobile

Ở bài trước, chúng ta đã xây dựng thành công một giao diện tĩnh với màn hình "Hello World". Nhưng một mobile app thực sự không thể chỉ đứng im như một bức tranh. Nó phải "sống": Nút bấm phải đếm được số lần nhấn, danh sách phải tự động tải thêm dữ liệu khi vuốt, và giao diện phải thay đổi khi người dùng đăng nhập.

Để làm cho ứng dụng phản hồi lại các tương tác đó, chúng ta cần một công cụ mạnh mẽ. Trong thế giới React Native, công cụ đó mang tên React Hooks.

Bài viết này sẽ giúp bạn làm chủ 3 "vũ khí" quan trọng nhất: useState, useEffectuseRef. Bất kể ứng dụng của bạn phức tạp đến đâu, chúng đều được xây dựng dựa trên 3 nền tảng cốt lõi này.

1. useState: Bộ nhớ ngắn hạn của giao diện

Khái niệm quan trọng nhất trong React Native là State (Trạng thái). State là nơi lưu trữ dữ liệu của một màn hình.

Quy tắc tối thượng: Bất cứ khi nào State thay đổi, React Native sẽ tự động vẽ lại (re-render) màn hình để cập nhật giao diện mới nhất.

Để tạo ra State, chúng ta sử dụng Hook useState.

Cú pháp và Cách hoạt động

Hãy tưởng tượng chúng ta đang làm một nút "Thả tim" (Like) cho một bài viết.

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

export default function LikeButton() {
  // Khai báo state 'likes' với giá trị ban đầu là 0
  const [likes, setLikes] = useState(0)

  return (
    <View style={styles.container}>
      <Text style={styles.text}>Số lượt thích: {likes}</Text>

      <TouchableOpacity
        style={styles.button}
        onPress={() => setLikes(likes + 1)} // Cập nhật state khi nhấn
      >
        <Text style={styles.buttonText}>❤️ Thả tim</Text>
      </TouchableOpacity>
    </View>
  )
}

const styles = StyleSheet.create({
  container: { flex: 1, justifyContent: 'center', alignItems: 'center' },
  text: { fontSize: 20, marginBottom: 20 },
  button: { backgroundColor: '#ff4757', padding: 15, borderRadius: 10 },
  buttonText: { color: 'white', fontWeight: 'bold' },
})

Mổ xẻ cú pháp const [likes, setLikes] = useState(0):

  • 0: Là giá trị khởi tạo ban đầu.
  • likes: Là biến chứa giá trị hiện tại (giống như việc đọc dữ liệu).
  • setLikes: Là một hàm "kỳ diệu". Mỗi khi bạn muốn thay đổi số lượt thích, bạn KHÔNG ĐƯỢC phép viết likes = 1. Bạn bắt buộc phải gọi setLikes(1). Khi hàm này được gọi, React Native lập tức biết rằng dữ liệu đã đổi và sẽ cập nhật lại dòng chữ trên màn hình điện thoại.

2. useEffect: Quản lý vòng đời & Tác dụng phụ

Nếu useState là "trí nhớ", thì useEffect là "giác quan" và "hành động" của ứng dụng.

useEffect được sử dụng để xử lý các Side Effects (Tác dụng phụ) - tức là những việc xảy ra bên ngoài việc vẽ giao diện, chẳng hạn như: gọi API lấy danh sách bài viết từ server, thiết lập bộ đếm thời gian (timer), hay lắng nghe vị trí GPS.

Các giai đoạn cốt lõi của useEffect

Cú pháp của useEffect nhận vào hai tham số: Một hàm thực thi, và một Mảng phụ thuộc (Dependency Array). Tuỳ vào mảng phụ thuộc này, useEffect sẽ hoạt động theo 3 cách khác nhau:

Cách 1: Chạy MỘT LẦN DUY NHẤT khi màn hình vừa mở lên (Mảng rỗng []). Đây là cách dùng phổ biến nhất, thường để gọi API lấy dữ liệu ban đầu.

useEffect(() => {
  console.log('Màn hình vừa được mở. Bắt đầu tải dữ liệu từ Server...')
  // Gọi API ở đây...
}, []) // Mảng rỗng báo hiệu chỉ chạy 1 lần lúc khởi tạo (Mount)

Cách 2: Chạy MỖI KHI một State cụ thể thay đổi (Có biến trong mảng). Ví dụ, mỗi khi người dùng đổi từ khóa tìm kiếm, bạn muốn gọi lại API để tìm món hàng mới.

const [keyword, setKeyword] = useState('')

useEffect(() => {
  console.log(`Bạn vừa gõ từ khóa: ${keyword}. Đang tìm kiếm...`)
}, [keyword]) // Chỉ chạy lại khi biến 'keyword' thay đổi

Cách 3: Dọn dẹp rác trước khi rời đi (Cleanup Function). Trong Mobile, việc tối ưu bộ nhớ là sống còn. Nếu bạn bật một bộ đếm thời gian khi vào màn hình, bạn phải tắt nó đi khi người dùng chuyển sang màn hình khác (Unmount), nếu không ứng dụng sẽ bị tràn bộ nhớ (Memory Leak) và văng app (Crash).

useEffect(() => {
  const timer = setInterval(() => {
    console.log('Tích tắc...')
  }, 1000)

  // Hàm return bên trong useEffect đóng vai trò dọn dẹp
  return () => {
    clearInterval(timer)
    console.log('Đã dọn dẹp bộ đếm khi thoát màn hình!')
  }
}, [])

3. useRef: "Hộp lưu trữ" không gây Re-render

Có một hạn chế của useState: Mỗi lần bạn dùng setState để cập nhật dữ liệu, toàn bộ màn hình sẽ bị vẽ lại. Nếu bạn có một dữ liệu thay đổi liên tục nhưng KHÔNG cần hiển thị lên giao diện, việc dùng useState sẽ làm app bị giật lag nghiêm trọng.

Đó là lúc useRef tỏa sáng. useRef giống như một chiếc hộp lưu trữ dữ liệu:

  1. Bạn có thể thay đổi dữ liệu trong hộp thoải mái.
  2. Việc thay đổi này không bao giờ làm màn hình bị vẽ lại.
  3. Dữ liệu trong hộp vẫn được giữ nguyên không bị mất đi qua mỗi lần màn hình render.

Ứng dụng phổ biến nhất trong React Native

Ngoài việc lưu các giá trị ngầm, useRef thường được dùng để can thiệp trực tiếp vào một Component (Native View). Ví dụ: Tự động nhảy con trỏ chuột vào ô nhập liệu (TextInput).

import React, { useRef } from 'react'
import { View, TextInput, TouchableOpacity, Text } from 'react-native'

export default function InputScreen() {
  // Tạo một reference (hộp chứa) để trỏ tới TextInput
  const inputRef = useRef(null)

  const handleFocus = () => {
    // Ra lệnh cho TextInput bật bàn phím lên
    inputRef.current.focus()
  }

  return (
    <View style={{ flex: 1, padding: 20 }}>
      {/* Gắn ref vào TextInput */}
      <TextInput
        ref={inputRef}
        style={{ borderWidth: 1, padding: 10, marginBottom: 10 }}
        placeholder="Nhập tên của bạn..."
      />

      <TouchableOpacity onPress={handleFocus} style={{ backgroundColor: 'blue', padding: 10 }}>
        <Text style={{ color: 'white', textAlign: 'center' }}>Bấm để gõ chữ</Text>
      </TouchableOpacity>
    </View>
  )
}

Kết luận: Khi nào dùng cái nào?

Để không bị nhầm lẫn khi mới bắt đầu, hãy nhớ quy tắc thần chú này:

  • Dữ liệu thay đổi + Cần hiện lên màn hình ➡️ Dùng useState.
  • Cần làm việc phụ (gọi API, hẹn giờ) ➡️ Dùng useEffect.
  • Dữ liệu thay đổi + KHÔNG cần hiện lên màn hình HOẶC Cần điều khiển một component ➡️ Dùng useRef.

Với 3 vũ khí này, bạn đã nắm trong tay 80% sức mạnh cốt lõi của React. Ứng dụng của bạn giờ đây đã có thể ghi nhớ, suy nghĩ và phản hồi.

Tuy nhiên, các màn hình của chúng ta hiện đang được sắp xếp khá lộn xộn. Ở bài tiếp theo, chúng ta sẽ quay lại với phần Giao diện để học cách sử dụng các "viên gạch" xây nhà chuẩn chỉ nhất của Native App.

Bài viết liên quan

React Native là gì? Tại sao nên dùng nó để lập trình Mobile?

Tìm hiểu sức mạnh của React Native và nền tảng Expo giúp bạn tạo ứng dụng di động nhanh chóng mà không cần cài đặt rắc rối.

Phân tích luồng chạy ứng dụng Expo chi tiết từ A-Z

Tìm hiểu cách ứng dụng khởi chạy, làm chủ thư mục app/, cấu trúc file cơ bản và phân tích cú pháp JSX một cách cực kỳ dễ hiểu.

Tìm hiểu 5 Core Components quan trọng nhất trong React Native

Hướng dẫn cách sử dụng các Core Components trong React Native. Nắm vững View, Text, Image, TextInput và ScrollView để xây dựng mọi giao diện mobile.

Cách làm chủ StyleSheet & Flexbox Layout trong React Native

Nắm vững nghệ thuật tạo kiểu với StyleSheet và làm chủ hệ thống Flexbox trong React Native. Hướng dẫn chi tiết flexDirection, justifyContent, alignItems.