Напоминание о Bottom Tab Navigation
Перед тем как углубиться в типизацию, давайте вспомним, как мы на прошлом занятии создали Bottom Tab Navigation. Вот простой пример:
import React from 'react';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import HomeScreen from './HomeScreen';
import SettingsScreen from './SettingsScreen';
const Tab = createBottomTabNavigator();
const MyTabs = () => {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
);
};
export default MyTabs;
Мы создали навигатор Tab.Navigator с двумя экранами — Home и Settings. Всё просто, правда? Но попробуйте передать в SettingsScreen параметры, а затем их использовать. Без типизации вы будете гадать, какие данные должны быть переданы и что там будет внутри.
Создание интерфейса для типов параметров Tab Navigation
Теперь перейдём к типизации. Будем использовать интерфейс TypeScript для описания параметров, которые может принимать каждый экран.
Пример типизации параметров:
import { NavigatorScreenParams } from '@react-navigation/native';
// Интерфейс для параметров экранов в Tab Navigator
interface TabParamList {
Home: undefined; // Экран Home не принимает параметров
Settings: { userId: string }; // Экран Settings принимает параметр userId
}
- Home: мы указываем
undefined, так как для этого экрана параметров не требуется. - Settings: экран принимает параметр
userId, который является строкой. Теперь ваш код чётко знает, какие параметры должны быть переданы.
Применение интерфейса в Tab Navigator
Типизация в createBottomTabNavigator выполняется с помощью дженерика (generic). Попробуем:
import React from 'react';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import HomeScreen from './HomeScreen';
import SettingsScreen from './SettingsScreen';
// Определяем TabParamList
interface TabParamList {
Home: undefined;
Settings: { userId: string };
}
// Создаём Tab Navigator с типами
const Tab = createBottomTabNavigator<TabParamList>();
const MyTabs = () => {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen
name="Settings"
component={SettingsScreen}
initialParams={{ userId: 'default_user' }} // Указываем начальные параметры
/>
</Tab.Navigator>
);
};
export default MyTabs;
Отлично! Теперь createBottomTabNavigator знает, что все экраны должны соответствовать интерфейсу TabParamList.
Типизация параметров экрана с useRoute
Теперь давайте типизируем параметры в самих экранах. Используем хук useRoute, чтобы получить данные.
Пример: использование параметров в HomeScreen
import React from 'react';
import { View, Text } from 'react-native';
import { useRoute, RouteProp } from '@react-navigation/native';
// Определяем типы маршрута для Home
type HomeRouteProp = RouteProp<TabParamList, 'Settings'>;
const SettingsScreen = () => {
const route = useRoute<HomeRouteProp>();
return (
<View>
<Text>User ID: {route.params.userId}</Text>
</View>
);
};
export default SettingsScreen;
Разбираем, что здесь происходит:
RouteProp: этот тип описывает маршрут для конкретного экрана и берёт данные изTabParamList.useRoute<HomeRouteProp>: мы указываем конкретно дляSettings, что он ожидает параметрuserId. Теперь, если вы забудете передатьuserIdпри переходе на этот экран, TypeScript предупредит об этом.
Типизация параметров для навигации с useNavigation
А как быть, если вы хотите программно перемещаться между экранами? Для этого есть хук useNavigation. Давайте добавим типизацию и сюда.
import { useNavigation } from '@react-navigation/native';
import { BottomTabNavigationProp } from '@react-navigation/bottom-tabs';
// Определяем тип навигатора
type SettingsScreenNavigationProp = BottomTabNavigationProp<TabParamList, 'Settings'>;
const HomeScreen = () => {
const navigation = useNavigation<SettingsScreenNavigationProp>();
const goToSettings = () => {
navigation.navigate('Settings', { userId: '12345' });
};
return (
<View>
<Button title="Go to Settings" onPress={goToSettings} />
</View>
);
};
export default HomeScreen;
Здесь мы типизировали навигацию для Settings, явно указав, что он требует параметр userId. Теперь TypeScript не даст нам случайно передать что-то, что не соответствует типу.
Часто задаваемые вопросы и типичные ошибки
Почему нельзя просто использовать any?
Использование any разрушает всю суть TypeScript. Вы лишаетесь проверки типов, что может привести к ошибкам, которые обнаруживаются только на этапе выполнения. Это как ездить на машине без тормозов: возможно, вы не упадёте с обрыва, но шансы есть.
А что делать, если экран не принимает параметры?
Если экран не принимает параметры, всегда указывайте undefined в интерфейсе. Например:
Home: undefined;
Как обработать опциональные параметры?
Для опциональных параметров используйте тип ?:
Settings: { userId?: string };
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ