![]()
Ở bài trước, bạn đã tận mắt chứng kiến "phép màu" khi dòng code trên máy tính xuất hiện ngay lập tức trên màn hình điện thoại thông qua Expo Go. Nhưng phép màu thực chất chỉ là công nghệ mà chúng ta chưa hiểu rõ.
Khi chạy lệnh npx create-expo-app, hệ thống đã tự động tạo ra một loạt các thư mục và file cấu hình. Chắc hẳn bạn đang bối rối: "File này để làm gì? Xóa đi có sao không? Tôi phải viết code bắt đầu từ đâu?".
Trong bài viết này, chúng ta sẽ đi vào dự án, mổ xẻ từng thành phần và phân tích xem một chương trình "Hello World" trong React Native thực sự hoạt động như thế nào.
1. Giải mã cấu trúc thư mục dự án Expo
Nếu bạn dùng phiên bản Expo mới nhất (với kiến trúc Expo Router), khi mở dự án bằng VS Code, bạn sẽ thấy một danh sách các file và thư mục. Dưới đây là những "nhân vật" quan trọng nhất mà bạn cần nhớ mặt:
my-first-app/
├── app/ # Chứa các màn hình (screens) của ứng dụng
│ ├── _layout.tsx
│ ├── index.tsx
│ └── profile.tsx
├── assets/ # Chứa hình ảnh, âm thanh, font chữ...
├── node_modules/ # Chứa các thư viện (được tự động tạo)
├── app.json # Cấu hình ứng dụng (tên, icon, splash...)
└── package.json # Danh sách thư viện và các lệnh chạy
Thư mục app
Đây là nơi bạn sẽ dành 99% thời gian để làm việc. Với Expo Router hiện đại, mọi file bạn tạo trong thư mục app/ sẽ tự động trở thành một màn hình (screen) trong ứng dụng.
- Ví dụ: File
app/index.tsxchính là màn hình trang chủ. Fileapp/profile.tsxsẽ là màn hình trang cá nhân. Khái niệm này gọi là File-based routing (Điều hướng dựa trên file), cực kỳ trực quan và dễ quản lý.
Thư mục assets
Đúng như tên gọi, đây là nơi chứa các tài nguyên tĩnh không phải là code. Hình ảnh (.png, .jpg), file âm thanh, font chữ tùy chỉnh hay icon ứng dụng của bạn đều sẽ được "nhét" vào đây.
Thư mục node_modules
Thư mục này chứa toàn bộ các thư viện bên thứ ba mà dự án của bạn sử dụng (bao gồm cả bản thân React và React Native).
- Lưu ý sống còn: KHÔNG BAO GIỜ được sửa code trong thư mục này, và cũng không bao giờ tải thư mục này lên GitHub/GitLab vì nó rất nặng. Nó sẽ tự động được tạo ra khi bạn chạy lệnh
npm install.
File app.json
Đây như là "Căn cước công dân" của ứng dụng. Mọi thông tin cốt lõi để đưa app lên Store đều nằm ở đây:
- Tên ứng dụng hiển thị trên màn hình điện thoại (
name). - Biểu tượng ứng dụng (
icon). - Màn hình chờ khi khởi động app (
splash). - Tên gói (Bundle ID cho iOS và Package Name cho Android).
File package.json
File này liệt kê tất cả các "nhân sự" (thư viện) đang làm việc trong dự án của bạn cùng với số phiên bản của chúng. Nó cũng chứa các dòng lệnh viết tắt (scripts) để bạn khởi động dự án như npm start.
2. Viết code "Hello World" và phân tích cú pháp
Bây giờ, hãy mở file app/index.tsx (hoặc App.js nếu bạn dùng phiên bản cũ) và xóa sạch mọi thứ. Chúng ta sẽ tự tay viết lại chương trình "Hello World" từ con số 0 để hiểu rõ bản chất.
Hãy gõ đoạn code sau vào:
import React from 'react'
import { View, Text, StyleSheet } from 'react-native'
export default function HomeScreen() {
return (
<View style={styles.container}>
<Text style={styles.title}>Hello World!</Text>
<Text style={styles.subtitle}>Chào mừng đến với React Native</Text>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
title: {
fontSize: 24,
fontWeight: 'bold',
color: 'blue',
},
subtitle: {
fontSize: 16,
color: 'gray',
marginTop: 10,
},
})
Ngay khi bạn nhấn Save, màn hình điện thoại sẽ hiện ra dòng chữ căn giữa cực kỳ ngay ngắn. Vậy đoạn code này có ý nghĩa gì? Chúng ta chia làm 3 phần:
Phần 1: Import - Khai báo công cụ
import React from 'react'
import { View, Text, StyleSheet } from 'react-native'
Để sử dụng thẻ View hay Text, bạn phải "xin phép" và lấy chúng ra từ thư viện lõi react-native.
Phần 2: Component - Xây dựng Giao diện (JSX)
export default function HomeScreen() {
return <View style={styles.container}>{/* Code hiển thị ở đây */}</View>
}
Mỗi màn hình hay một phần giao diện trong React Native được gọi là một Component. Ở đây ta tạo một function tên là HomeScreen.
- Điểm đặc biệt là thay vì trả về dữ liệu tính toán thông thường, function này trả về JSX (một cú pháp viết giao diện trông giống hệt HTML nhưng hoạt động bằng JavaScript).
- Thẻ
<View>đóng vai trò như thẻ<div>trong Web, dùng để bọc và chứa các thành phần khác. - Thẻ
<Text>dùng để hiển thị chữ. Mọi văn bản đều BẮT BUỘC phải nằm trong thẻ<Text>.
Phần 3: StyleSheet - Trang điểm cho ứng dụng
const styles = StyleSheet.create({ ... })
Thay vì dùng file .css tách biệt như lập trình Web, React Native sử dụng công cụ StyleSheet để tạo CSS ngay trong file JavaScript. Nó giúp code chạy nhanh hơn và báo lỗi ngay lập tức nếu bạn gõ sai tên thuộc tính.
3. Luồng hoạt động bên dưới: Ứng dụng chạy thế nào?
Để bạn trở thành một lập trình viên giỏi chứ không chỉ là "thợ gõ code", bạn cần hiểu luồng chạy ngầm khi bạn mở ứng dụng Expo:
- Khởi động: Khi bạn chạm vào icon ứng dụng, hệ điều hành (iOS/Android) sẽ tìm đọc file cấu hình (
app.jsonđã dịch ra Native) để biết tên app, hiển thị lên màn hình Splash Screen. - Nạp JavaScript: Máy ảo JavaScript bên trong thiết bị (Hermes Engine) bắt đầu đọc code của bạn. Nó chạy thẳng vào thư mục
app/và tìm kiếm màn hình mặc định (index.tsx). - Chuyển đổi (The Bridge / JSI): React Native đọc các thẻ
<View>,<Text>của bạn và ra lệnh cho hệ điều hành: "Này iOS, hãy vẽ cho tôi một cáiUIView. Này Android, hãy vẽ một cáiTextView". - Hiển thị: Giao diện bản địa được render lên màn hình điện thoại của người dùng, mang lại cảm giác mượt mà 100% Native.
Kết luận: Cấu trúc dự án Expo không còn đáng sợ
Sau bài này, cấu trúc dự án Expo đã không còn là một "chiếc hộp đen" đáng sợ nữa. Bạn đã nắm được app.json là "bộ não", app/ là "trái tim", và biết cách một Component kết hợp giữa Logic (JS) - Giao diện (JSX) - Thẩm mỹ (StyleSheet) hoạt động ra sao.
Tuy nhiên, ứng dụng thực tế không chỉ đứng im một chỗ. Chữ và số trên màn hình cần phải thay đổi khi người dùng tương tác (ví dụ: bấm nút đếm số, nhập chữ vào ô tìm kiếm). Để làm được điều đó, chúng ta phải làm quen với những công cụ mạnh mẽ hơn trong React.
Hẹn gặp bạn ở những bài hướng dẫn tiếp theo!