Nguyễn Đình Cường
0 comment
09 Nov, 2026
Một ứng dụng React Native thực tế gồm nhiều màn hình, và React Navigation là thư viện điều hướng được dùng rộng rãi nhất. Bài này hướng dẫn kết hợp Stack và Tab, truyền tham số giữa các màn hình cũng như khai báo kiểu với TypeScript.
Với dự án Expo hoặc React Native, bạn cài thư viện lõi và các thư viện hỗ trợ theo hướng dẫn trên trang chính thức, sau đó cài loại navigator cần dùng:
npm install @react-navigation/native @react-navigation/native-stack @react-navigation/bottom-tabs
Ngoài ra cần các phụ thuộc như react-native-screens và react-native-safe-area-context; hãy làm theo tài liệu để đúng phiên bản của dự án.
Stack hoạt động như ngăn xếp: mở màn hình mới trượt lên trên, quay lại thì trượt ra. Đây là kiểu điều hướng cơ bản nhất.
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
type RootStackParamList = {
Home: undefined;
Detail: { productId: string };
};
const Stack = createNativeStackNavigator<RootStackParamList>();
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} options={{ title: 'Trang chủ' }} />
<Stack.Screen name="Detail" component={DetailScreen} options={{ title: 'Chi tiết' }} />
</Stack.Navigator>
</NavigationContainer>
);
}
import type { NativeStackScreenProps } from '@react-navigation/native-stack';
type HomeProps = NativeStackScreenProps<RootStackParamList, 'Home'>;
function HomeScreen({ navigation }: HomeProps) {
return (
<Button
title="Xem sản phẩm"
onPress={() => navigation.navigate('Detail', { productId: '42' })}
/>
);
}
type DetailProps = NativeStackScreenProps<RootStackParamList, 'Detail'>;
function DetailScreen({ route }: DetailProps) {
const { productId } = route.params;
return <Text>Sản phẩm số {productId}</Text>;
}
Việc khai báo RootStackParamList giúp TypeScript báo lỗi ngay nếu bạn quên truyền tham số hoặc gõ sai tên màn hình.
Tab phù hợp cho các khu vực chính của ứng dụng như Trang chủ, Tìm kiếm, Cá nhân. Người dùng chuyển qua lại mà không mất trạng thái mỗi tab.
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
const Tab = createBottomTabNavigator();
function MainTabs() {
return (
<Tab.Navigator>
<Tab.Screen name="Feed" component={FeedScreen} />
<Tab.Screen name="Search" component={SearchScreen} />
<Tab.Screen name="Profile" component={ProfileScreen} />
</Tab.Navigator>
);
}
Mẫu phổ biến là đặt Tab làm một màn hình trong Stack gốc. Khi mở màn hình chi tiết, nó phủ lên trên cả thanh tab, còn khi quay lại thì thanh tab hiện ra như cũ. Bạn chỉ cần khai báo MainTabs làm một Stack.Screen và đặt Detail cùng cấp.
Cách thường dùng là hiển thị có điều kiện: nếu chưa đăng nhập thì Stack chỉ chứa các màn hình Login và Đăng ký, nếu đã đăng nhập thì chứa các màn hình chính. Cách này tự động loại bỏ các màn hình cũ khi trạng thái đổi, người dùng không thể bấm Back để quay về màn hình đăng nhập.
useFocusEffect để tải lại dữ liệu mỗi khi màn hình được hiển thị trở lại.navigation.goBack() và popToTop() hợp lý để điều khiển ngăn xếp.Nắm Stack, Tab và cách truyền tham số có kiểu là đủ để dựng điều hướng cho đa số ứng dụng. Hãy bắt đầu với cấu trúc đơn giản, thêm Drawer hoặc modal khi thật sự cần.
Mỗi màn hình có thể tùy biến qua thuộc tính options: tiêu đề, nút bên phải, ẩn thanh tiêu đề, kiểu hiệu ứng chuyển. Bạn cũng có thể đặt giá trị chung cho cả navigator bằng screenOptions để mọi màn hình nhất quán về màu và kiểu chữ. Nếu tiêu đề phụ thuộc dữ liệu truyền vào, đặt nó động từ route.params bằng hàm options.
Về hành vi quay lại, hãy nhớ rằng Android có nút hoặc cử chỉ Back của hệ thống. Nếu màn hình có nội dung nhập dở, dùng sự kiện beforeRemove để hỏi xác nhận trước khi rời đi. Với các luồng như đăng nhập, dùng thao tác reset hoặc thay thế màn hình để người dùng không quay lại được bước trước đó. Cuối cùng, kiểm thử điều hướng trên cả hai nền tảng, vì cử chỉ vuốt mép trên iOS và nút Back trên Android có thể cho kết quả khác nhau.
Một lỗi phổ biến là điều hướng tới tên màn hình không tồn tại hoặc ở navigator khác; TypeScript giúp bắt lỗi này nếu bạn khai báo kiểu đầy đủ. Lỗi khác là đặt NavigationContainer lồng nhau, trong khi chỉ được có một ở gốc ứng dụng. Nhiều bạn cũng quên bọc ứng dụng trong vùng an toàn nên nội dung bị che bởi tai thỏ. Khi màn hình không cập nhật sau khi quay lại, hãy kiểm tra xem bạn có cần useFocusEffect để tải lại dữ liệu hay không, vì màn hình ở dưới trong ngăn xếp không bị hủy mà vẫn được giữ nguyên.
Nếu muốn thực hành điều hướng trong một dự án trọn vẹn, hãy xem các khóa học trên codebem.com.
Nguyễn Đình Cường
0 comment