Mobile Dev

React Native: Xây Dựng App iOS & Android Bằng JavaScript

Tìm hiểu React Native - framework của Meta cho phép developer web dễ dàng chuyển sang mobile development

10 phút đọc
NhiTuyen Tech Blog Team
React Native: Xây Dựng App iOS & Android Bằng JavaScript

React Native: JavaScript Cho Mobile Development

React Native là framework của Meta (Facebook) cho phép bạn xây dựng ứng dụng mobile thực sự (không phải hybrid) bằng JavaScript và React. Nếu bạn đã biết web development, đây là cách nhanh nhất để bắt đầu làm mobile app!

React Native Development

Tại Sao Chọn React Native?

1. Dùng Kiến Thức Web Có Sẵn

// Nếu bạn biết React web, bạn đã biết 80% React Native!
import React, { useState } from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';

// Component y chang React web
function Counter() {
  const [count, setCount] = useState(0);
  
  return (
    <View style={styles.container}>
      <Text style={styles.title}>Đếm: {count}</Text>
      <Button 
        title="Tăng" 
        onPress={() => setCount(count + 1)} 
      />
    </View>
  );
}

// StyleSheet giống CSS
const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#fff',
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 20,
  }
});

// Nếu biết React, học RN chỉ mất vài ngày! 🚀

2. Native Performance

Chú thích: React Native không phải là WebView (như Cordova/PhoneGap). Nó biên dịch thành native UI components thật sự!

// <View> → UIView (iOS) hoặc android.view (Android)
// <Text> → UILabel (iOS) hoặc TextView (Android)
// <Image> → UIImageView (iOS) hoặc ImageView (Android)

// App chạy smooth như native app! ⚡

3. Fast Refresh - DX Tuyệt Vời

// Sửa code, thấy kết quả NGAY LẬP TỨC
// Không cần rebuild app!

function WelcomeScreen() {
  return (
    <View>
      <Text>Xin chào!</Text>
      {/* Thay đổi text này và save file */}
      {/* App update < 1 giây! ⚡ */}
    </View>
  );
}

Fast Refresh

Setup Project

Expo - Cách Dễ Nhất

Chú thích: Expo là bộ công cụ giúp bạn bắt đầu React Native mà không cần cài đặt Xcode/Android Studio phức tạp.

# Cài Expo CLI
npm install -g expo-cli

# Tạo project mới
npx create-expo-app MyApp

# Vào thư mục
cd MyApp

# Chạy app
npm start

# Quét QR code bằng điện thoại → App chạy ngay! 📱

React Native CLI - Full Control

# Cài React Native CLI
npm install -g react-native-cli

# Tạo project
npx react-native init MyApp

# Chạy trên iOS
npx react-native run-ios

# Chạy trên Android
npx react-native run-android

# Cần Xcode (Mac) hoặc Android Studio

Core Components

Layout với Flexbox

Chú thích: Flexbox trong React Native mặc định là flexDirection: 'column' (khác với web là row)

import { View, Text } from 'react-native';

function FlexboxLayout() {
  return (
    <View style={{ flex: 1, flexDirection: 'column' }}>
      {/* Header */}
      <View style={{ height: 80, backgroundColor: '#007AFF' }}>
        <Text style={{ color: 'white', fontSize: 20, padding: 20 }}>
          Header
        </Text>
      </View>
      
      {/* Content - chiếm hết không gian còn lại */}
      <View style={{ flex: 1, backgroundColor: '#F5F5F5' }}>
        <Text>Nội dung chính</Text>
      </View>
      
      {/* Footer */}
      <View style={{ height: 60, backgroundColor: '#333' }}>
        <Text style={{ color: 'white' }}>Footer</Text>
      </View>
    </View>
  );
}

Flexbox Layout

ScrollView & FlatList

import { ScrollView, FlatList, Text } from 'react-native';

// ScrollView - Cho nội dung tĩnh
function StaticContent() {
  return (
    <ScrollView>
      <Text>Đoạn 1...</Text>
      <Text>Đoạn 2...</Text>
      {/* Tất cả render cùng lúc */}
    </ScrollView>
  );
}

// FlatList - Cho danh sách dài (hiệu quả hơn)
function PostsList() {
  const posts = [
    { id: '1', title: 'Bài viết 1' },
    { id: '2', title: 'Bài viết 2' },
    // ... 1000 items
  ];
  
  return (
    <FlatList
      data={posts}
      // Chỉ render items đang hiển thị trên màn hình
      // → Performance tốt với 10,000 items! 🚀
      renderItem={({ item }) => (
        <Text style={{ padding: 20 }}>{item.title}</Text>
      )}
      keyExtractor={item => item.id}
    />
  );
}

TextInput & Form

import { TextInput, Button, Alert } from 'react-native';
import { useState } from 'react';

function LoginForm() {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  
  const handleLogin = () => {
    if (!email || !password) {
      Alert.alert('Lỗi', 'Vui lòng nhập đầy đủ thông tin');
      return;
    }
    
    // Call API login
    console.log('Đăng nhập với:', email, password);
  };
  
  return (
    <View style={{ padding: 20 }}>
      <TextInput
        placeholder="Email"
        value={email}
        onChangeText={setEmail}
        keyboardType="email-address"
        autoCapitalize="none"
        style={{
          borderWidth: 1,
          borderColor: '#ccc',
          padding: 10,
          marginBottom: 10,
          borderRadius: 5,
        }}
      />
      
      <TextInput
        placeholder="Mật khẩu"
        value={password}
        onChangeText={setPassword}
        secureTextEntry  // Ẩn mật khẩu
        style={{
          borderWidth: 1,
          borderColor: '#ccc',
          padding: 10,
          marginBottom: 20,
          borderRadius: 5,
        }}
      />
      
      <Button title="Đăng nhập" onPress={handleLogin} />
    </View>
  );
}

Forms

React Navigation

Chú thích: React Navigation là thư viện routing phổ biến nhất cho React Native, tương tự như React Router cho web.

# Cài đặt
npm install @react-navigation/native
npm install @react-navigation/native-stack
npm install react-native-screens react-native-safe-area-context
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

const Stack = createNativeStackNavigator();

// Screen components
function HomeScreen({ navigation }) {
  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Text style={{ fontSize: 24, marginBottom: 20 }}>Trang chủ</Text>
      <Button
        title="Xem chi tiết"
        onPress={() => navigation.navigate('Details', { 
          itemId: 42,
          title: 'Sản phẩm ABC'
        })}
      />
    </View>
  );
}

function DetailsScreen({ route, navigation }) {
  const { itemId, title } = route.params;
  
  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Text>Chi tiết: {title}</Text>
      <Text>ID: {itemId}</Text>
      <Button
        title="Quay lại"
        onPress={() => navigation.goBack()}
      />
    </View>
  );
}

// App với Navigation
export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen 
          name="Home" 
          component={HomeScreen}
          options={{ title: 'Trang chủ' }}
        />
        <Stack.Screen 
          name="Details" 
          component={DetailsScreen}
          options={{ title: 'Chi tiết' }}
        />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

Navigation

Tab Navigation

import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { Ionicons } from '@expo/vector-icons';

const Tab = createBottomTabNavigator();

function App() {
  return (
    <NavigationContainer>
      <Tab.Navigator
        screenOptions={({ route }) => ({
          tabBarIcon: ({ focused, color, size }) => {
            let iconName;
            
            if (route.name === 'Trang chủ') {
              iconName = focused ? 'home' : 'home-outline';
            } else if (route.name === 'Cài đặt') {
              iconName = focused ? 'settings' : 'settings-outline';
            }
            
            return <Ionicons name={iconName} size={size} color={color} />;
          },
        })}
      >
        <Tab.Screen name="Trang chủ" component={HomeScreen} />
        <Tab.Screen name="Tìm kiếm" component={SearchScreen} />
        <Tab.Screen name="Cài đặt" component={SettingsScreen} />
      </Tab.Navigator>
    </NavigationContainer>
  );
}

Styling

StyleSheet API

import { StyleSheet } from 'react-native';

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    padding: 20,
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    color: '#333',
    marginBottom: 10,
  },
  button: {
    backgroundColor: '#007AFF',
    padding: 15,
    borderRadius: 8,
    alignItems: 'center',
  },
  buttonText: {
    color: 'white',
    fontSize: 16,
    fontWeight: '600',
  }
});

// Sử dụng
<View style={styles.container}>
  <Text style={styles.title}>Tiêu đề</Text>
  <TouchableOpacity style={styles.button}>
    <Text style={styles.buttonText}>Nhấn vào đây</Text>
  </TouchableOpacity>
</View>

Styled Components

Chú thích: Styled Components cho phép viết CSS-in-JS giống như trong React web.

npm install styled-components
import styled from 'styled-components/native';

const Container = styled.View`
  flex: 1;
  background-color: #fff;
  padding: 20px;
`;

const Title = styled.Text`
  font-size: 24px;
  font-weight: bold;
  color: #333;
  margin-bottom: 10px;
`;

const Button = styled.TouchableOpacity`
  background-color: #007AFF;
  padding: 15px;
  border-radius: 8px;
  align-items: center;
`;

const ButtonText = styled.Text`
  color: white;
  font-size: 16px;
  font-weight: 600;
`;

// Sử dụng
function MyComponent() {
  return (
    <Container>
      <Title>Tiêu đề</Title>
      <Button>
        <ButtonText>Nhấn vào đây</ButtonText>
      </Button>
    </Container>
  );
}

Styling

API Calls & State Management

Fetch Data

import { useEffect, useState } from 'react';
import { ActivityIndicator, FlatList, Text } from 'react-native';

function PostsList() {
  const [posts, setPosts] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  
  useEffect(() => {
    fetchPosts();
  }, []);
  
  const fetchPosts = async () => {
    try {
      const response = await fetch('https://api.example.com/posts');
      const data = await response.json();
      setPosts(data);
    } catch (err) {
      setError('Không thể tải dữ liệu');
    } finally {
      setLoading(false);
    }
  };
  
  if (loading) {
    return <ActivityIndicator size="large" color="#007AFF" />;
  }
  
  if (error) {
    return <Text style={{ color: 'red' }}>{error}</Text>;
  }
  
  return (
    <FlatList
      data={posts}
      renderItem={({ item }) => (
        <View style={{ padding: 20, borderBottomWidth: 1 }}>
          <Text style={{ fontSize: 18, fontWeight: 'bold' }}>
            {item.title}
          </Text>
          <Text style={{ color: '#666', marginTop: 5 }}>
            {item.excerpt}
          </Text>
        </View>
      )}
      keyExtractor={item => item.id.toString()}
      refreshing={loading}
      onRefresh={fetchPosts}  // Pull to refresh!
    />
  );
}

Redux Toolkit

Chú thích: Redux quản lý state global của app, giống như trong React web.

npm install @reduxjs/toolkit react-redux
// store/userSlice.js
import { createSlice } from '@reduxjs/toolkit';

const userSlice = createSlice({
  name: 'user',
  initialState: {
    currentUser: null,
    isLoggedIn: false,
  },
  reducers: {
    login: (state, action) => {
      state.currentUser = action.payload;
      state.isLoggedIn = true;
    },
    logout: (state) => {
      state.currentUser = null;
      state.isLoggedIn = false;
    }
  }
});

export const { login, logout } = userSlice.actions;
export default userSlice.reducer;

// store/index.js
import { configureStore } from '@reduxjs/toolkit';
import userReducer from './userSlice';

export const store = configureStore({
  reducer: {
    user: userReducer,
  }
});

// App.js
import { Provider } from 'react-redux';
import { store } from './store';

export default function App() {
  return (
    <Provider store={store}>
      <NavigationContainer>
        {/* App content */}
      </NavigationContainer>
    </Provider>
  );
}

// Sử dụng trong component
import { useSelector, useDispatch } from 'react-redux';
import { login, logout } from './store/userSlice';

function ProfileScreen() {
  const user = useSelector(state => state.user.currentUser);
  const dispatch = useDispatch();
  
  return (
    <View>
      {user ? (
        <>
          <Text>Xin chào, {user.name}!</Text>
          <Button 
            title="Đăng xuất" 
            onPress={() => dispatch(logout())} 
          />
        </>
      ) : (
        <Button 
          title="Đăng nhập" 
          onPress={() => dispatch(login({ name: 'John' }))} 
        />
      )}
    </View>
  );
}

State Management

Native Modules

Camera

npm install react-native-vision-camera
import { Camera, useCameraDevices } from 'react-native-vision-camera';

function CameraScreen() {
  const devices = useCameraDevices();
  const device = devices.back;
  
  if (device == null) return <Text>Loading...</Text>;
  
  return (
    <Camera
      style={{ flex: 1 }}
      device={device}
      isActive={true}
      photo={true}
    />
  );
}

Location

npm install @react-native-community/geolocation
import Geolocation from '@react-native-community/geolocation';

function LocationScreen() {
  const [location, setLocation] = useState(null);
  
  useEffect(() => {
    Geolocation.getCurrentPosition(
      position => {
        setLocation({
          latitude: position.coords.latitude,
          longitude: position.coords.longitude,
        });
      },
      error => console.log(error),
      { enableHighAccuracy: true }
    );
  }, []);
  
  return (
    <View>
      {location ? (
        <Text>
          Vị trí: {location.latitude}, {location.longitude}
        </Text>
      ) : (
        <Text>Đang lấy vị trí...</Text>
      )}
    </View>
  );
}

Native Features

Performance Tips

1. Sử dụng PureComponent/React.memo

import React from 'react';

// Chỉ re-render khi props thay đổi
const PostItem = React.memo(({ title, excerpt }) => {
  return (
    <View style={{ padding: 20 }}>
      <Text style={{ fontSize: 18, fontWeight: 'bold' }}>{title}</Text>
      <Text>{excerpt}</Text>
    </View>
  );
});

// Tránh re-render không cần thiết! 🚀

2. Optimize Images

import FastImage from 'react-native-fast-image';

// Thay vì Image component
<FastImage
  source={{
    uri: 'https://example.com/image.jpg',
    priority: FastImage.priority.high,
  }}
  style={{ width: 300, height: 200 }}
  resizeMode={FastImage.resizeMode.cover}
/>

// Cache và load nhanh hơn! ⚡

3. Use FlatList thay vì ScrollView

// ❌ Chậm với list dài
<ScrollView>
  {data.map(item => <Item key={item.id} {...item} />)}
</ScrollView>

// ✅ Nhanh với 10,000 items
<FlatList
  data={data}
  renderItem={({ item }) => <Item {...item} />}
  keyExtractor={item => item.id}
  windowSize={10}  // Chỉ render 10 items
  removeClippedSubviews={true}
  maxToRenderPerBatch={10}
/>

Testing

npm install --save-dev @testing-library/react-native jest
import { render, fireEvent } from '@testing-library/react-native';
import Counter from './Counter';

test('counter increments', () => {
  const { getByText } = render(<Counter />);
  
  const button = getByText('Tăng');
  fireEvent.press(button);
  
  expect(getByText('Đếm: 1')).toBeTruthy();
});

Testing

Build & Deploy

iOS

# Build cho iOS
cd ios
pod install
cd ..

# Open Xcode
open ios/MyApp.xcworkspace

# Archive → Upload to App Store

Android

# Generate release APK
cd android
./gradlew assembleRelease

# APK tại: android/app/build/outputs/apk/release/

# Upload lên Google Play Console

React Native vs Flutter

FeatureReact NativeFlutter
Ngôn ngữJavaScript (quen thuộc)Dart (mới học)
Community⭐⭐⭐⭐⭐ Rất lớn⭐⭐⭐⭐ Đang tăng
Performance⭐⭐⭐⭐ Tốt⭐⭐⭐⭐⭐ Rất tốt
Native feel✅ Native components⚠️ Custom rendering
Learning curveDễ (nếu biết React)Medium
Hot reload

Kết Luận

React Native là lựa chọn tuyệt vời nếu:

  • ✅ Bạn đã biết JavaScript/React
  • ✅ Cần ship app nhanh
  • ✅ Team nhỏ, muốn code một lần cho 2 platform
  • ✅ App không cần performance cực cao (game 3D)
// Bắt đầu hành trình mobile development!
const yourJourney = {
  day1: 'Setup và Hello World',
  week1: 'Build todo app',
  month1: 'App hoàn chỉnh trên App Store',
  future: 'Mobile developer pro! 🚀'
};

console.log('Start coding now! 💪');

Success


Bạn đã build app React Native nào chưa? Chia sẻ trải nghiệm! 💬

Tags

#ReactNative #JavaScript #MobileDevelopment #iOS #Android #CrossPlatform #React

Tags:

#React Native #JavaScript #Mobile Development #iOS #Android #Cross-platform

Chia sẻ bài viết:

Bài viết liên quan

Bài viết liên quan 1
Bài viết liên quan 2
Bài viết liên quan 3