Навигатор стека
Навигация по экранам важна при работе с мобильными приложениями. React Navigation - потрясающая библиотека, которая позволяет вам создавать различные типы навигации в вашем проекте React Native.
Когда я впервые начал работать с React Native, я подумал, что это немного сбивает с толку, как перемещаться по экранам. Это было еще сложнее, потому что я хотел использовать Typescript и большинство примеров в Интернете, написанных с использованием Javascript.
Моя цель сейчас - показать вам, что я узнал, создавая несколько типов навигаторов с использованием Typescript, чтобы вы не страдали, как я вначале.
Итак, приступим к настройке базового Навигатора стека, который позволит вам перемещаться между экраном приветствия и входа в систему и экраном регистрации, как показано на следующем каркасе:
Настройте свой проект и React Navigation
Начнем с создания проекта на основе выставки. Убедитесь, что на вашем компьютере установлен expo. Если вы еще не установили его, вы можете сделать это, запустив:
npm install -g expo-cli
После установки давайте создадим проект, выполнив следующую команду,
expo init StackNavigatorExample
После того, как expo завершит инициализацию вашего проекта, вам нужно будет установить React Navigation и все зависимости, необходимые для его работы. Итак, приступим к настройке:
cd
в свой проект, запустивcd StackNavigatorExample
2. Установите React Navigation,
npm i @react-navigation/native
3. Установите одноранговые зависимости.
expo install react-native-gesture-handler react-native-reanimated react-native-screens react-native-safe-area-context @react-native-community/masked-view
4. Установите Stack Navigator из React Navigation.
npm install @react-navigation/stack
5. Начни кодирование!
Создание структуры проекта и нашего навигатора
Теперь, когда у вас настроен наш проект, вы можете приступить к созданию всех экранов, которые будут обрабатываться навигатором. Начнем с создания структуры нашего проекта.
Давайте добавим следующие каталоги для хранения каждого экрана:
src/screens/Auth/LoginScreen
src/screens/Auth/SignupScreen
src/screens/WelcomeScreen
Ваш проект должен выглядеть так:
Теперь, когда у вас есть эта базовая структура проекта, давайте создадим навигатор. Чтобы сделать проект модульным, я создам отдельный каталог для всех моих навигаторов внутри src/navigators/AuthFlowNavigator/index.tsx
.
index.tsx
file должен выглядеть так:
import React from 'react'; import { createStackNavigator } from '@react-navigation/stack'; import WelcomeScreen from '../../screens/WelcomeScreen'; import LoginScreen from '../../screens/Auth/LoginScreen'; import SignupScreen, { SignupParams } from '../../screens/Auth/SignupScreen'; export enum AppScreens { Welcome = 'Welcome', Login = 'Login', Signup = 'Signup' } export type AuthStackParamList = { Login: undefined; Signup: SignupParams; Welcome: undefined; }; const AuthStack = createStackNavigator<AuthStackParamList>(); const AuthFlowNavigator: React.FunctionComponent = () => { return ( <AuthStack.Navigator headerMode="none"> <AuthStack.Screen name={AppScreens.Welcome} component={WelcomeScreen} /> <AuthStack.Screen name={AppScreens.Login} component={LoginScreen} /> <AuthStack.Screen name={AppScreens.Signup} component={SignupScreen} /> </AuthStack.Navigator> ); }; export default AuthFlowNavigator;
😮 Вам может быть интересно прямо сейчас, что делает весь этот код. Но это довольно просто. Я объясню это шаг за шагом,
- Определите перечисление с именами всех экранов в вашем приложении. Это позволит вам перемещаться между ними, не добавляя жестко запрограммированные имена внутри ваших экранов, это менее подвержено ошибкам, поскольку оно будет принимать связанное имя повсюду в вашем коде.
export enum AppScreens { Welcome = 'Welcome', Login = 'Login', Signup = 'Signup' }
2. Определите, какие параметры можно передавать на каждый из экранов навигатора,
export type AuthStackParamList = { Login: undefined; Signup: SignupParams; Welcome: undefined; };
Как мы видим в этом случае, единственный экран, который что-то получает, - это SignupScreen
, мы скоро перейдем к определению его параметров.
3. Наконец, мы должны создать наш навигатор и экспортировать его, чтобы мы могли использовать его на нашем App.tsx
, поскольку это точка входа в наше приложение.
const AuthStack = createStackNavigator<AuthStackParamList>(); const AuthFlowNavigator: React.FunctionComponent = () => { return ( <AuthStack.Navigator headerMode="none"> <AuthStack.Screen name={AppScreens.Welcome} component={WelcomeScreen} /> <AuthStack.Screen name={AppScreens.Login} component={LoginScreen} /> <AuthStack.Screen name={AppScreens.Signup} component={SignupScreen} /> </AuthStack.Navigator> ); }; export default AuthFlowNavigator;
Как видите, я добавил в навигатор опору headerMode="none"
. По сути, он скрывает заголовок по умолчанию с кнопкой back
, которую вы всегда получаете по умолчанию в навигаторе стека.
Еще одна вещь, которую следует учитывать в приведенном выше коде, - это то, что мы добавляем все экраны, которые хотим иметь в стеке, с помощью следующего кода:
<AuthStack.Screen name={AppScreens.Welcome} component={WelcomeScreen} />
В нашем примере мы просто добавляем 3 экрана: один для экрана приветствия, второй для экрана входа в систему и третий для экрана регистрации.
4. Обновите свой App.tsx
файл, чтобы он выглядел следующим образом:
import React from 'react'; import { NavigationContainer } from '@react-navigation/native'; import AuthFlowNavigator from './src/navigators/AuthFlowNavigator'; export default function App() { return ( <NavigationContainer> <AuthFlowNavigator /> </NavigationContainer> ); }
Таким образом, наш AuthFlowNavigator сможет отображать экран, который мы определили выше.
Экран приветствия
Теперь, когда у нас настроен навигатор, давайте добавим код на наш начальный экран (src/screens/WelcomeScreen/index.tsx
),
import React from 'react'; import { SafeAreaView, StyleSheet, Text, View, Button } from 'react-native'; import { StackNavigationProp } from '@react-navigation/stack'; import { AuthStackParamList, AppScreens } from '../../navigators/AuthFlowNavigator'; type WelcomeScreenNavigationProps = StackNavigationProp<AuthStackParamList, AppScreens.Welcome>; interface WelcomeScreenProps { navigation: WelcomeScreenNavigationProps; } const styles = StyleSheet.create({ btnNextContainer: { alignSelf: 'flex-end' }, container: { flex: 1, alignItems: 'center', justifyContent: 'space-between', margin: 10 }, welcome: { fontSize: 30 }, welcomeContainer: { alignItems: 'center', justifyContent: 'center', flex: 1, width: '100%' } }); const WelcomeScreen: React.FunctionComponent<WelcomeScreenProps> = (props) => { const { navigation } = props; return ( <SafeAreaView style={styles.container}> <View style={styles.welcomeContainer}> <Text style={styles.welcome}>Welcome</Text> </View> <View style={styles.btnNextContainer}> <Button title="NEXT" onPress={() => navigation.navigate(AppScreens.Login)} /> </View> </SafeAreaView> ); }; export default WelcomeScreen;
Это должно дать вам следующий результат:
Как видно из следующего кода,
<Button title="NEXT" onPress={() => navigation.navigate(AppScreens.Login)} />
мы отображаем кнопку, которая позволяет нам перейти к следующему экрану в стеке. Посмотрите, как мы используем AppScreens.Login
, перечисление, которое мы определили ранее и которое помогает нам узнать, какие экраны у него есть в нашем приложении, и предотвращает неправильный ввод имени экрана.
Экран входа в систему
Теперь давайте добавим код для LoginScreen
внутрь src/screens/auth/LoginScreen/index.tsx
. Должно получиться так:
import React, { useState } from 'react'; import { SafeAreaView, StyleSheet, Text, TextInput, Button, View } from 'react-native'; import { AppScreens, AuthStackParamList } from '../../../navigators/AuthFlowNavigator'; import { StackNavigationProp } from '@react-navigation/stack'; type LoginScreenNavigationProps = StackNavigationProp<AuthStackParamList, AppScreens.Login>; interface LoginScreenProps { navigation: LoginScreenNavigationProps; } const styles = StyleSheet.create({ btnSignupContainer: { alignItems: 'center' }, container: { flex: 1, alignItems: 'center', justifyContent: 'space-between', margin: 10 }, textInput: { borderRadius: 5, borderWidth: 1, borderColor: 'grey', marginTop: 4, padding: 2, width: '100%' }, textInputContainer: { width: '100%' }, txtHello: { fontSize: 30 } }); const LoginScreen: React.FunctionComponent<LoginScreenProps> = (props) => { const { navigation } = props; const [username, setUsername] = useState<string>(''); return ( <SafeAreaView style={styles.container}> <Text style={styles.txtHello}>Hello</Text> <View style={styles.textInputContainer}> <TextInput value={username} placeholder="username" style={styles.textInput} onChangeText={(text) => setUsername(text)} /> <TextInput placeholder="password" secureTextEntry={true} style={styles.textInput} /> </View> <View style={styles.btnSignupContainer}> <Text>Or</Text> <Button title="Signup" onPress={() => navigation.navigate(AppScreens.Signup, { username })} /> </View> </SafeAreaView> ); }; export default LoginScreen;
И это должно дать вам следующий результат:
Как вы можете видеть, код, связанный с навигацией, почти такой же по сравнению с WelcomeScreen
, единственное главное отличие состоит в том, что мы передаем значениеusername
в SignupScreen
, передавая в качестве второго аргумента объект navigate()
, содержащий всю необходимую нам информацию. перейти к следующему экрану:
<Button title="Signup" onPress={() => navigation.navigate(AppScreens.Signup, { username })} />
Экран регистрации
Наконец, добавьте следующий код к нашему SignupScreen
по адресу src/screens/auth/SignupScreen/index.tsx
,
import React from 'react'; import { SafeAreaView, StyleSheet, Text, TextInput, Button, View } from 'react-native'; import { AppScreens, AuthStackParamList } from '../../../navigators/AuthFlowNavigator'; import { StackNavigationProp } from '@react-navigation/stack'; type SignupScreenNavigationProps = StackNavigationProp<AuthStackParamList, AppScreens.Signup>; export type SignupParams = { username: string; }; interface SignupScreenProps { route: { params: SignupParams }; navigation: SignupScreenNavigationProps; } const styles = StyleSheet.create({ btnLoginContainer: { alignSelf: 'center' }, container: { flex: 1, alignItems: 'center', justifyContent: 'space-between', margin: 10 }, txtSignupScreen: { fontSize: 30 }, txtSignupScreenContainer: { flex: 1, alignItems: 'center', justifyContent: 'center' }, txtUsername: { fontSize: 25, color: 'grey' } }); const SignupScreen: React.FunctionComponent<SignupScreenProps> = (props) => { const { navigation, route } = props; const { params } = route; const { username } = params; return ( <SafeAreaView style={styles.container}> <View style={styles.txtSignupScreenContainer}> <Text style={styles.txtSignupScreen}>SignupScreen</Text> <Text style={styles.txtUsername}>{username}</Text> </View> <View style={styles.btnLoginContainer}> <Text>have an account?</Text> <Button title="Login" onPress={() => navigation.pop()} /> </View> </SafeAreaView> ); }; export default SignupScreen;
На этом экране вы заметите некоторые изменения по сравнению с предыдущим экраном. Здесь мы должны сообщить экрану, какие параметры он получает. Мы делаем это в этом разделе,
export type SignupParams = { username: string; }; interface SignupScreenProps { route: { params: SignupParams }; navigation: SignupScreenNavigationProps; }
Приведенный выше код должен дать нам следующий результат:
Вы заметите, что благодаря выполненной настройке мы можем передавать значение username
. Вы можете ввести что-нибудь в тексте username text field
и нажать кнопку signup
, и вы увидите значение, отображаемое на экране регистрации:
Заключение
Как видите, настроить навигатор с помощью React Navigation довольно просто. Если вы уже знакомы с некоторыми концепциями Typescript, то код, который мы рассмотрели, должен показаться вам довольно знакомым. Если вы используете Javascript в своем проекте, настройка навигатора работает точно так же, просто удалите все типы и интерфейсы, и все должно работать нормально.
Создание других типов навигаторов также действительно прямолинейно. После знакомства с React Navigation вы увидите, как легко добавлять новые экраны в свой проект!
Я загрузил репо в свою учетную запись GitHub на случай, если вы захотите клонировать его и сразу же использовать 😃