# React Native: Xay Dung Ung Dung Di Dong Hoan Chinh Nam 2026 > Huong dan day du ve phat trien ung dung di dong iOS va Android voi React Native. Tu thiet lap moi truong den trien khai, tat ca kien thuc can ban de ban bat dau. - Published: 2026-01-10 - Updated: 2026-04-06 - Author: SharpSkill - Tags: react native, mobile development, javascript, ios, android - Reading time: 15 min --- React Native cho phép xây dựng các ứng dụng di động native cho iOS và Android từ một mã nguồn JavaScript duy nhất. Được duy trì bởi Meta và được sử dụng trong các ứng dụng như Instagram, Facebook và Discord, framework này mang lại trải nghiệm phát triển nhanh chóng đồng thời tạo ra các ứng dụng có hiệu suất cao. > **Tại sao chọn React Native vào năm 2026?** > > Với kiến trúc mới (Fabric và TurboModules) đã ổn định, React Native mang lại hiệu suất gần như native trong khi vẫn duy trì năng suất phát triển web. Hơn 40% trong số 500 ứng dụng hàng đầu sử dụng React Native. ## Development Environment Setup Trước khi bắt đầu, việc cài đặt các công cụ cần thiết là bước không thể thiếu. React Native cung cấp hai cách tiếp cận: Expo (được khuyến nghị cho người mới) và React Native CLI (cho nhu cầu kiểm soát sâu hơn). ```bash # setup.sh # Node.js installation (LTS version recommended) # Check installed version node --version # >= 18.x required npm --version # >= 9.x required # Install Expo CLI tool globally npm install -g expo-cli # Create a new project with Expo npx create-expo-app@latest MyApp --template blank-typescript # Navigate to the project cd MyApp # Start the development server npx expo start ``` Expo giúp đơn giản hóa đáng kể quá trình phát triển bằng cách tự động xử lý cấu hình native. Để kiểm thử ứng dụng, bạn có thể sử dụng ứng dụng Expo Go trên điện thoại để quét mã QR được hiển thị. ```bash # structure.sh # Generated project structure MyApp/ ├── App.tsx # Application entry point ├── app.json # Expo configuration ├── package.json # Dependencies ├── tsconfig.json # TypeScript configuration ├── babel.config.js # Babel configuration └── assets/ # Images and resources ├── icon.png └── splash.png ``` ## Core React Native Components React Native cung cấp các component native thay thế các phần tử HTML. Mỗi component được chuyển đổi trực tiếp thành các component native trên iOS hoặc Android. ```tsx // App.tsx import React from 'react'; import { View, Text, StyleSheet, SafeAreaView, StatusBar } from 'react-native'; // Main application component export default function App() { return ( // SafeAreaView prevents overlap with status bar {/* StatusBar configures system bar appearance */} {/* View is the equivalent of div */} {/* Text is required to display text */} Welcome to MyApp A React Native application ); } // StyleSheet.create optimizes styles for native const styles = StyleSheet.create({ container: { flex: 1, // Takes all available space backgroundColor: '#ffffff', }, header: { padding: 20, alignItems: 'center', // Centers horizontally justifyContent: 'center', // Centers vertically }, title: { fontSize: 24, fontWeight: 'bold', color: '#1a1a1a', marginBottom: 8, }, subtitle: { fontSize: 16, color: '#666666', }, }); ``` > **Flexbox là mặc định** > > React Native sử dụng Flexbox với `flexDirection: 'column'` làm mặc định (khác với web sử dụng `row`). Sự khác biệt này rất quan trọng khi thiết kế bố cục giao diện. ## Handling User Interactions Các tương tác chạm được quản lý thông qua các component chuyên biệt. Mỗi loại tương tác có component riêng để tối ưu hóa hiệu suất. ```tsx // components/InteractiveButton.tsx import React, { useState } from 'react'; import { TouchableOpacity, TouchableHighlight, Pressable, Text, StyleSheet, View, } from 'react-native'; // Button component with different interaction styles export function InteractiveButton() { const [count, setCount] = useState(0); return ( {/* TouchableOpacity reduces opacity on touch */} setCount(c => c + 1)} > Counter: {count} {/* Pressable offers more control over states */} [ styles.button, styles.pressableButton, pressed && styles.buttonPressed, ]} onPress={() => console.log('Pressed!')} onLongPress={() => console.log('Long press!')} > {({ pressed }) => ( {pressed ? 'Pressed!' : 'Press here'} )} ); } const styles = StyleSheet.create({ container: { gap: 16, padding: 20, }, button: { backgroundColor: '#007AFF', paddingVertical: 14, paddingHorizontal: 28, borderRadius: 10, alignItems: 'center', }, pressableButton: { backgroundColor: '#34C759', }, buttonPressed: { backgroundColor: '#2DA44E', transform: [{ scale: 0.98 }], }, buttonText: { color: '#ffffff', fontSize: 16, fontWeight: '600', }, }); ``` ## Screen Navigation with React Navigation Điều hướng là yếu tố thiết yếu trong mọi ứng dụng di động. React Navigation là giải pháp tiêu chuẩn, cung cấp nhiều kiểu điều hướng phù hợp với các mô hình di động. ```bash # install-navigation.sh # Installing navigation dependencies npx expo install @react-navigation/native npx expo install @react-navigation/native-stack npx expo install react-native-screens react-native-safe-area-context ``` ```tsx // App.tsx import React from 'react'; import { NavigationContainer } from '@react-navigation/native'; import { createNativeStackNavigator } from '@react-navigation/native-stack'; // Screen imports import { HomeScreen } from './screens/HomeScreen'; import { DetailScreen } from './screens/DetailScreen'; import { ProfileScreen } from './screens/ProfileScreen'; // Type definition for TypeScript navigation export type RootStackParamList = { Home: undefined; // No parameters Detail: { itemId: number; title: string }; // Required parameters Profile: { userId?: string }; // Optional parameter }; // Creating typed navigator const Stack = createNativeStackNavigator(); export default function App() { return ( // NavigationContainer manages navigation state ({ title: route.params.title })} /> ); } ``` ```tsx // screens/HomeScreen.tsx import React from 'react'; import { View, Text, FlatList, TouchableOpacity, StyleSheet } from 'react-native'; import { NativeStackScreenProps } from '@react-navigation/native-stack'; import { RootStackParamList } from '../App'; // Typing navigation props type Props = NativeStackScreenProps; // Sample data const ITEMS = [ { id: 1, title: 'First item' }, { id: 2, title: 'Second item' }, { id: 3, title: 'Third item' }, ]; export function HomeScreen({ navigation }: Props) { return ( {/* FlatList for performant lists */} item.id.toString()} renderItem={({ item }) => ( { // Navigation with typed parameters navigation.navigate('Detail', { itemId: item.id, title: item.title, }); }} > {item.title} )} ItemSeparatorComponent={() => } /> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#f5f5f5', }, item: { backgroundColor: '#ffffff', padding: 20, }, itemText: { fontSize: 16, color: '#1a1a1a', }, separator: { height: 1, backgroundColor: '#e0e0e0', }, }); ``` ## State Management with Context and Hooks Đối với việc quản lý state ở mức đơn giản đến trung bình, React Context kết hợp với hooks mang lại giải pháp hiệu quả mà không cần thư viện bên ngoài. ```tsx // context/AuthContext.tsx import React, { createContext, useContext, useState, useCallback } from 'react'; // Types for authentication interface User { id: string; email: string; name: string; } interface AuthContextType { user: User | null; isLoading: boolean; signIn: (email: string, password: string) => Promise; signOut: () => void; } // Creating context with default value const AuthContext = createContext(undefined); // Provider that wraps the application export function AuthProvider({ children }: { children: React.ReactNode }) { const [user, setUser] = useState(null); const [isLoading, setIsLoading] = useState(false); // Sign in function const signIn = useCallback(async (email: string, password: string) => { setIsLoading(true); try { // Simulated API call const response = await fetch('https://api.example.com/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, password }), }); const data = await response.json(); setUser(data.user); } catch (error) { console.error('Login error:', error); throw error; } finally { setIsLoading(false); } }, []); // Sign out function const signOut = useCallback(() => { setUser(null); }, []); return ( {children} ); } // Custom hook to use the context export function useAuth() { const context = useContext(AuthContext); if (context === undefined) { throw new Error('useAuth must be used within an AuthProvider'); } return context; } ``` ```tsx // screens/LoginScreen.tsx import React, { useState } from 'react'; import { View, Text, TextInput, TouchableOpacity, StyleSheet, ActivityIndicator, Alert, } from 'react-native'; import { useAuth } from '../context/AuthContext'; export function LoginScreen() { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const { signIn, isLoading } = useAuth(); // Form submission handler const handleSubmit = async () => { if (!email || !password) { Alert.alert('Error', 'Please fill in all fields'); return; } try { await signIn(email, password); } catch (error) { Alert.alert('Error', 'Invalid credentials'); } }; return ( Login {isLoading ? ( ) : ( Sign In )} ); } const styles = StyleSheet.create({ container: { flex: 1, padding: 20, justifyContent: 'center', backgroundColor: '#ffffff', }, title: { fontSize: 28, fontWeight: 'bold', marginBottom: 32, textAlign: 'center', }, input: { borderWidth: 1, borderColor: '#e0e0e0', borderRadius: 10, padding: 16, marginBottom: 16, fontSize: 16, backgroundColor: '#f9f9f9', }, button: { backgroundColor: '#007AFF', padding: 16, borderRadius: 10, alignItems: 'center', marginTop: 8, }, buttonDisabled: { backgroundColor: '#99c9ff', }, buttonText: { color: '#ffffff', fontSize: 18, fontWeight: '600', }, }); ``` > **State toàn cục và state cục bộ** > > Đối với các ứng dụng phức tạp hơn với nhiều state chia sẻ, các giải pháp như Zustand hoặc Redux Toolkit có thể phù hợp hơn. Context tối ưu cho state ít thay đổi (theme, xác thực). ## API Calls and Data Management Giao tiếp với backend là phần cốt lõi của mọi ứng dụng di động. Dưới đây là một mô hình vững chắc sử dụng lớp trừu tượng cho các lời gọi API. ```tsx // services/api.ts // Base API configuration const API_BASE_URL = 'https://api.example.com'; // Type for API errors interface ApiError { message: string; code: string; status: number; } // Utility function for requests async function request( endpoint: string, options: RequestInit = {} ): Promise { const url = `${API_BASE_URL}${endpoint}`; const config: RequestInit = { ...options, headers: { 'Content-Type': 'application/json', ...options.headers, }, }; try { const response = await fetch(url, config); if (!response.ok) { const error: ApiError = await response.json(); throw new Error(error.message || 'An error occurred'); } return response.json(); } catch (error) { // Network error handling if (error instanceof TypeError) { throw new Error('Network connection issue'); } throw error; } } // Types for entities interface Product { id: string; name: string; price: number; description: string; imageUrl: string; } // Products service export const productApi = { // Get all products getAll: () => request('/products'), // Get product by ID getById: (id: string) => request(`/products/${id}`), // Create a product create: (data: Omit) => request('/products', { method: 'POST', body: JSON.stringify(data), }), // Update a product update: (id: string, data: Partial) => request(`/products/${id}`, { method: 'PATCH', body: JSON.stringify(data), }), }; ``` ```tsx // hooks/useProducts.ts import { useState, useEffect, useCallback } from 'react'; import { productApi } from '../services/api'; interface Product { id: string; name: string; price: number; description: string; imageUrl: string; } // Custom hook for product management export function useProducts() { const [products, setProducts] = useState([]); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); // Initial products loading const fetchProducts = useCallback(async () => { setIsLoading(true); setError(null); try { const data = await productApi.getAll(); setProducts(data); } catch (err) { setError(err instanceof Error ? err.message : 'Unknown error'); } finally { setIsLoading(false); } }, []); // Refresh (pull-to-refresh) const refresh = useCallback(async () => { await fetchProducts(); }, [fetchProducts]); // Load on mount useEffect(() => { fetchProducts(); }, [fetchProducts]); return { products, isLoading, error, refresh, }; } ``` ```tsx // screens/ProductListScreen.tsx import React from 'react'; import { View, Text, FlatList, Image, StyleSheet, RefreshControl, ActivityIndicator, } from 'react-native'; import { useProducts } from '../hooks/useProducts'; export function ProductListScreen() { const { products, isLoading, error, refresh } = useProducts(); // Display during initial loading if (isLoading && products.length === 0) { return ( Loading... ); } // Display on error if (error) { return ( {error} ); } return ( item.id} contentContainerStyle={styles.list} // Pull-to-refresh refreshControl={ } renderItem={({ item }) => ( {item.name} ${item.price.toFixed(2)} )} /> ); } const styles = StyleSheet.create({ centered: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: 20, }, loadingText: { marginTop: 12, fontSize: 16, color: '#666666', }, errorText: { fontSize: 16, color: '#FF3B30', textAlign: 'center', }, list: { padding: 16, }, card: { backgroundColor: '#ffffff', borderRadius: 12, marginBottom: 16, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 4, elevation: 3, }, image: { width: '100%', height: 200, borderTopLeftRadius: 12, borderTopRightRadius: 12, }, cardContent: { padding: 16, }, productName: { fontSize: 18, fontWeight: '600', color: '#1a1a1a', marginBottom: 4, }, productPrice: { fontSize: 16, color: '#007AFF', fontWeight: '500', }, }); ``` ## Local Data Storage Lưu trữ cục bộ cho phép duy trì dữ liệu giữa các phiên làm việc. AsyncStorage là giải pháp tiêu chuẩn cho dữ liệu đơn giản, trong khi SQLite phù hợp với dữ liệu có cấu trúc phức tạp. ```tsx // services/storage.ts import AsyncStorage from '@react-native-async-storage/async-storage'; // Required installation: npx expo install @react-native-async-storage/async-storage // Centralized storage keys const STORAGE_KEYS = { USER_TOKEN: '@app/user_token', USER_PREFERENCES: '@app/user_preferences', ONBOARDING_COMPLETE: '@app/onboarding_complete', } as const; // Types for user preferences interface UserPreferences { theme: 'light' | 'dark' | 'system'; notifications: boolean; language: string; } // Typed storage service export const storage = { // Authentication token async getToken(): Promise { return AsyncStorage.getItem(STORAGE_KEYS.USER_TOKEN); }, async setToken(token: string): Promise { await AsyncStorage.setItem(STORAGE_KEYS.USER_TOKEN, token); }, async removeToken(): Promise { await AsyncStorage.removeItem(STORAGE_KEYS.USER_TOKEN); }, // User preferences (JSON object) async getPreferences(): Promise { const data = await AsyncStorage.getItem(STORAGE_KEYS.USER_PREFERENCES); return data ? JSON.parse(data) : null; }, async setPreferences(prefs: UserPreferences): Promise { await AsyncStorage.setItem( STORAGE_KEYS.USER_PREFERENCES, JSON.stringify(prefs) ); }, // Onboarding async isOnboardingComplete(): Promise { const value = await AsyncStorage.getItem(STORAGE_KEYS.ONBOARDING_COMPLETE); return value === 'true'; }, async setOnboardingComplete(): Promise { await AsyncStorage.setItem(STORAGE_KEYS.ONBOARDING_COMPLETE, 'true'); }, // Complete cleanup async clearAll(): Promise { const keys = Object.values(STORAGE_KEYS); await AsyncStorage.multiRemove(keys); }, }; ``` > **Bảo mật dữ liệu nhạy cảm** > > Đối với dữ liệu nhạy cảm như token xác thực, hãy sử dụng expo-secure-store — công cụ mã hóa dữ liệu thông qua iOS Keychain và Android Keystore. ## Responsive Styles and Theming Một ứng dụng chuyên nghiệp cần thích ứng với nhiều kích thước màn hình và hỗ trợ chế độ tối. ```tsx // theme/index.ts import { Dimensions, PixelRatio, Platform } from 'react-native'; const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } = Dimensions.get('window'); // Reference dimensions (iPhone 14) const guidelineBaseWidth = 390; const guidelineBaseHeight = 844; // Scaling functions export const scale = (size: number) => (SCREEN_WIDTH / guidelineBaseWidth) * size; export const verticalScale = (size: number) => (SCREEN_HEIGHT / guidelineBaseHeight) * size; export const moderateScale = (size: number, factor = 0.5) => size + (scale(size) - size) * factor; // Light theme export const lightTheme = { colors: { primary: '#007AFF', secondary: '#5856D6', success: '#34C759', warning: '#FF9500', error: '#FF3B30', background: '#FFFFFF', surface: '#F2F2F7', text: '#000000', textSecondary: '#8E8E93', border: '#E5E5EA', }, spacing: { xs: scale(4), sm: scale(8), md: scale(16), lg: scale(24), xl: scale(32), }, typography: { h1: { fontSize: moderateScale(32), fontWeight: 'bold' as const, lineHeight: moderateScale(40), }, h2: { fontSize: moderateScale(24), fontWeight: 'bold' as const, lineHeight: moderateScale(32), }, body: { fontSize: moderateScale(16), lineHeight: moderateScale(24), }, caption: { fontSize: moderateScale(14), lineHeight: moderateScale(20), }, }, borderRadius: { sm: scale(4), md: scale(8), lg: scale(12), full: 9999, }, }; // Dark theme export const darkTheme = { ...lightTheme, colors: { ...lightTheme.colors, background: '#000000', surface: '#1C1C1E', text: '#FFFFFF', textSecondary: '#8E8E93', border: '#38383A', }, }; export type Theme = typeof lightTheme; ``` ```tsx // context/ThemeContext.tsx import React, { createContext, useContext, useState, useEffect } from 'react'; import { useColorScheme } from 'react-native'; import { lightTheme, darkTheme, Theme } from '../theme'; import { storage } from '../services/storage'; interface ThemeContextType { theme: Theme; isDark: boolean; toggleTheme: () => void; setThemeMode: (mode: 'light' | 'dark' | 'system') => void; } const ThemeContext = createContext(undefined); export function ThemeProvider({ children }: { children: React.ReactNode }) { const systemColorScheme = useColorScheme(); const [themeMode, setThemeMode] = useState<'light' | 'dark' | 'system'>('system'); // Determine effective theme const isDark = themeMode === 'system' ? systemColorScheme === 'dark' : themeMode === 'dark'; const theme = isDark ? darkTheme : lightTheme; // Load preferences on startup useEffect(() => { storage.getPreferences().then((prefs) => { if (prefs?.theme) { setThemeMode(prefs.theme); } }); }, []); // Toggle between light and dark const toggleTheme = () => { const newMode = isDark ? 'light' : 'dark'; setThemeMode(newMode); storage.getPreferences().then((prefs) => { storage.setPreferences({ ...prefs, theme: newMode, notifications: prefs?.notifications ?? true, language: prefs?.language ?? 'en', }); }); }; return ( {children} ); } export function useTheme() { const context = useContext(ThemeContext); if (!context) { throw new Error('useTheme must be used within a ThemeProvider'); } return context; } ``` ## Preparing for Publication Trước khi phát hành ứng dụng, cần thực hiện một số bước cấu hình và tối ưu hóa. ```json // app.json { "expo": { "name": "MyApp", "slug": "my-app", "version": "1.0.0", "orientation": "portrait", "icon": "./assets/icon.png", "userInterfaceStyle": "automatic", "splash": { "image": "./assets/splash.png", "resizeMode": "contain", "backgroundColor": "#007AFF" }, "ios": { "supportsTablet": true, "bundleIdentifier": "com.example.myapp", "buildNumber": "1" }, "android": { "adaptiveIcon": { "foregroundImage": "./assets/adaptive-icon.png", "backgroundColor": "#007AFF" }, "package": "com.example.myapp", "versionCode": 1 }, "plugins": [ "expo-router" ] } } ``` ```bash # build.sh # EAS Build configuration (Expo Application Services) npm install -g eas-cli # Log in to Expo account eas login # Configure the project eas build:configure # Build for iOS (simulator) eas build --platform ios --profile development # Build for Android (test APK) eas build --platform android --profile preview # Production build eas build --platform all --profile production # Store submission eas submit --platform ios eas submit --platform android ``` > **Chứng chỉ và khóa** > > Phát hành trên iOS yêu cầu tài khoản Apple Developer ($99/năm) và trên Android yêu cầu tài khoản Google Play Console ($25 thanh toán một lần). EAS tự động quản lý các chứng chỉ ký số. ## Conclusion React Native cung cấp một cách tiếp cận hiệu quả để phát triển ứng dụng di động đa nền tảng. Những kiến thức cơ bản được trình bày trong hướng dẫn này giúp bạn xây dựng được các ứng dụng hoàn chỉnh và chuyên nghiệp. ### Danh sách kiểm tra cho ứng dụng React Native thành công - Thiết lập môi trường với Expo để khởi đầu nhanh chóng - Thành thạo các component cốt lõi: View, Text, TouchableOpacity, FlatList - Triển khai điều hướng với React Navigation và TypeScript typing - Quản lý state với Context API và custom hooks - Tổ chức các lời gọi API với lớp services chuyên biệt - Lưu trữ dữ liệu cục bộ với AsyncStorage - Xây dựng hệ thống theme responsive với hỗ trợ chế độ tối Tài liệu chính thức của React Native và Expo vẫn là nguồn tham khảo chính để đi sâu vào từng chủ đề. Hệ sinh thái phát triển rất nhanh, và các thư viện như React Query hoặc Zustand có thể đơn giản hóa hơn nữa việc quản lý dữ liệu trong các ứng dụng phức tạp hơn. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/vi/blog/react-native/react-native-building-complete-mobile-app