Обработка монтирования и размонтирования навигационных маршрутов в React Native
Опубликовано: 2022-03-10В этой статье мы рассмотрим монтирование и размонтирование навигационных маршрутов в React Native. Ожидаемое поведение вашего приложения заключается в том, что после выполнения условия аутентификации новый набор маршрутов навигации доступен только вошедшим в систему пользователям, в то время как другие экраны, которые отображались до аутентификации, удаляются и не могут быть возвращены, если только пользователь выходит из приложения.
В целях безопасности в вашем приложении защищенные маршруты предоставляют вам возможность отображать определенную информацию/контент в вашем приложении только для определенных пользователей, ограничивая при этом доступ неуполномоченных лиц.
Мы будем работать с Expo для этого проекта, потому что это поможет нам сосредоточиться на текущей проблеме, а не беспокоиться о множестве настроек. Точно такие же шаги, описанные в этой статье, можно выполнить для голого приложения React Native.
Вам нужно немного познакомиться с JavaScript и React Native , чтобы следовать этому руководству. Вот несколько важных вещей, с которыми вы уже должны быть знакомы:
- Пользовательские компоненты в React Native (как создавать компоненты, получать, передавать и использовать свойства в компоненте). Подробнее.
- Реагировать на навигацию. Подробнее.
- Навигатор стека в React Native. Подробнее.
- Базовые знания компонентов React Native Core (
<View/>
,<Text/>
и т. д.). Подробнее. -
AsyncStorage
. Подробнее. - Контекстный API. Подробнее.
Настройка проекта и базовая аутентификация
Если вы новичок в использовании expo и не знаете, как установить expo, посетите официальную документацию. После завершения установки приступайте к инициализации нового проекта React Native с помощью expo из нашей командной строки:
expo init navigation-project
Вам будет предложено несколько вариантов выбора базовой настройки:
В нашем случае давайте выберем первый вариант, чтобы настроить наш проект как пустой документ. Теперь дождитесь завершения установки зависимостей JavaScript.
Как только наше приложение настроено, мы можем изменить наш каталог на наш новый каталог проекта и открыть его в вашем любимом редакторе кода. Нам нужно установить библиотеку, которую мы будем использовать для AsyncStorage
и наших навигационных библиотек. Внутри каталога вашей папки в терминале вставьте приведенную выше команду и выберите шаблон ( blank
) для установки зависимостей нашего проекта.
Давайте посмотрим, для чего предназначена каждая из этих зависимостей:
- @react-native-community/async-storage
Как и localStorage в Интернете, это React Native API для сохранения данных на устройстве в парах ключ-значение. - @react-native-community/masked-view, react-native-screens, react-native-gesture-handle
Эти зависимости являются основными утилитами, которые используются большинством навигаторов для создания структуры навигации в приложении. (Подробнее читайте в разделе Начало работы с навигацией React Native.) - @реагировать-навигация/родной
Это зависимость для навигации React Native. - @реагировать-навигация/стек
Это зависимость для навигации по стеку в React Native.
npm install @react-native-community/async-storage @react-native-community/masked-view @react-navigation/native @react-navigation/stack react-native-screens react-native-gesture-handle
Чтобы запустить приложение, используйте expo start
из каталога приложения в вашем терминале. После запуска приложения вы можете использовать приложение expo со своего мобильного телефона для сканирования штрих-кода и просмотра приложения, или, если у вас есть эмулятор Android/симулятор IOS, вы можете открыть приложение через них из инструмента разработчика expo, который открывается в вашем браузере при запуске выставочного приложения. Для примеров изображений в этой статье мы будем использовать Genymotions, чтобы увидеть наш результат. Вот как будет выглядеть наш окончательный результат в Genymotions:
Структуры папок
Давайте создадим нашу структуру папок с самого начала, чтобы нам было легче работать с ней по мере продвижения:
Сначала нам нужны две папки:
- контекст
Эта папка будет содержать контекст для всего нашего приложения, так как мы будем работать с Context API для глобального управления состоянием. - Просмотры
Эта папка будет содержать как папку навигации, так и представления для разных экранов.
Идите вперед и создайте две папки в каталоге вашего проекта.
Внутри папки контекста создайте папку с именем authContext и создайте два файла внутри папки authContext :
- AuthContext.js ,
- AuthState.js .
Эти файлы понадобятся нам, когда мы начнем работать с Context API.
Теперь переходим в созданную нами папку views и создаем внутри нее еще две папки, а именно:
- навигация ,
- экраны .
Теперь, мы еще не закончили, внутри папки screens создайте еще две папки:
- postAuthScreens ,
- preAuthScreens .
Если вы правильно выполнили настройку папки, вот как ваша структура папок должна выглядеть на данный момент:
Создание нашего первого экрана
Теперь давайте создадим наш первый экран и назовем его welcomeScreen.js внутри папки preAuthScreens .
preAuthScreens > welcomeScreen.js
Вот содержимое нашего файла welcomeScreen.js :
import React from 'react'; import { View, Text, Button, StyleSheet, TextInput } from 'react-native'; const WelcomeScreen = () => { const onUserAuthentication = () => { console.log("User authentication button clicked") } return ( <View style={styles.container}> <Text style={styles.header}>Welcome to our App!</Text> <View> <TextInput style={styles.inputs} placeholder="Enter your email here.." /> <TextInput style={styles.inputs} secureTextEntry={true} placeholder="Enter your password here.." /> <Button title="AUTHENTICATE" onPress={onUserAuthentication} /> </View> </View> ) } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#fff', alignItems: 'center', justifyContent: 'center', }, header: { fontSize: 25, fontWeight: 'bold', marginBottom: 30 }, inputs: { width: 300, height: 40, marginBottom: 10, borderWidth: 1, } }) export default WelcomeScreen
Вот что мы сделали в блоке кода выше:
Во-первых, мы импортировали нужные нам вещи из библиотеки React Native, а именно View
, Text
, Button
, TextInput
. Далее мы создали наш функциональный компонент WelcomeScreen
.
Вы заметите, что мы импортировали StyleSheet
из React Native и использовали ее для определения стилей нашего заголовка, а также нашего <TextInput />
.
Наконец, мы экспортируем компонент WelcomeScreen
внизу кода.
Теперь, когда мы закончили с этим, давайте заставим этот компонент функционировать должным образом, используя хук useState
для хранения значений входных данных и обновления их состояний каждый раз, когда в полях ввода происходит изменение. Мы также импортируем хук useCallback
из React, так как он понадобится нам позже для удержания функции.
Во-первых, пока мы все еще находимся в компоненте WelcomeScreen
, нам нужно импортировать useState
и useCallback
из React.
import React, { useState, useCallback } from 'react';
Теперь внутри функционального компонента WelcomeScreen
создадим два состояния для электронной почты и пароля соответственно:
... const WelcomeScreen = () => { const [email, setEmail] = useState('') const [password, setPassword] = useState('') return ( ... ) } ...
Затем нам нужно изменить наши поля <TextInput />
, чтобы они получали их значение из соответствующих состояний и обновляли свое состояние при обновлении значения ввода:
import React, { useState, useCallback } from 'react'; import { View, Text, Button, StyleSheet, TextInput } from 'react-native'; const WelcomeScreen = () => { const [email, setEmail] = useState('') const [password, setPassword] = useState('') const onInputChange = (value, setState) => { setState(value); } return ( <View> ... <View> <TextInput style={styles.inputs} placeholder="Enter your email here.." value={email} onChangeText={(value) => onInputChange(value, setEmail)} /> <TextInput style={styles.inputs} secureTextEntry={true} placeholder="Enter your password here.." value={password} onChangeText={(value) => onInputChange(value, setPassword)} /> ... </View> </View> ) } ...
В приведенном выше коде вот что мы сделали:
- Мы сделали
value
каждого из текстовых входов, чтобы указать на их соответствующие состояния. - Мы добавили обработчик
onChangeText
в наши текстовые поля. Это запускается каждый раз, когда новое значение вводится или удаляется из полей ввода. - Мы вызвали нашу функцию
onInputChange
, которая принимает два аргумента:- Текущее
value
предоставляется обработчикомonChangeText
. - Сеттер состояния, которое должно быть обновлено (для первого поля ввода мы передаем
setEmail
а для второго —setPassword
. - Наконец, мы пишем нашу функцию
onInputChange
, и наша функция делает только одну вещь: обновляет соответствующие состояния с новым значением.
- Текущее
Следующее, над чем нам нужно поработать, это onUserAuthentication()
, которая вызывается всякий раз, когда нажимается кнопка отправки формы.
В идеале пользователь должен уже создать учетную запись, и вход в систему будет включать некоторую внутреннюю логику, чтобы проверить, что пользователь существует, а затем назначить пользователю токен. В нашем случае, поскольку мы не используем какой-либо бэкэнд, мы создадим объект, содержащий правильные данные для входа пользователя, а затем аутентифицируем пользователя только тогда, когда значения, которые они вводят, совпадают с нашими фиксированными значениями из объекта входа в систему email
и password
, которые мы будем Создайте.
Вот код, который нам нужен для этого:
... const correctAuthenticationDetails = { email: '[email protected]', password: 'password' } const WelcomeScreen = () => { ... // This function gets called when the `AUTHENTICATE` button is clicked const onUserAuthentication = () => { if ( email !== correctAuthenticationDetails.email || password !== correctAuthenticationDetails.password ) { alert('The email or password is incorrect') return } // In here, we will handle what happens if the login details are // correct } ... return ( ... ) } ...
Одна из первых вещей, которую вы заметите в приведенном выше коде, это то, что мы определили correctAuthenticationDetails
(объект, содержащий правильные данные для входа в систему, которые мы ожидаем от пользователя) вне функционального компонента WelcomeScreen()
.
Затем мы написали содержимое функции onUserAuthentication()
и использовали условный оператор, чтобы проверить, не совпадают ли email
или password
, хранящиеся в соответствующих состояниях, с теми, которые мы указали в нашем объекте.
Если вы хотите увидеть, что мы уже сделали, импортируйте компонент WelcomeScreen в свой App.js следующим образом:
Откройте файл App.js и замените весь код следующим:
import { StatusBar } from 'expo-status-bar'; import React from 'react'; import { View } from 'react-native'; import WelcomeScreen from './views/screens/preAuthScreens/welcomeScreen'; export default function App() { return ( <View> <StatusBar /> <WelcomeScreen /> </View> ); }
Внимательно изучив приведенный выше код, вы увидите, что мы импортировали компонент WelcomeScreen , а затем использовали его в функции App()
.
Вот как выглядит результат нашего WelcomeScreen
:
Теперь, когда мы закончили создание компонента WelcomeScreen , давайте двигаться дальше и начать работать с Context API для управления нашим глобальным состоянием.
Почему контекстный API?
Используя Context API, нам не нужно устанавливать какую-либо дополнительную библиотеку в ReactJS, его настройка менее утомительна, и это один из самых популярных способов обработки глобального состояния в ReactJS. Для упрощенного управления состоянием это хороший выбор.
Создание нашего контекста
Если вы помните, ранее мы создали контекстную папку и создали в ней подпапку с именем authContext .
Теперь давайте перейдем к файлу AuthContext.js в папке authContext и создадим наш контекст:
контекст > authContext > AuthContext.js
import React, { createContext } from 'react'; const AuthContext = createContext(); export default AuthContext;
Только что созданный AuthContext
содержит значение состояния loading
и значения состояния userToken
. В настоящее время в createContext
, который мы объявили в блоке кода выше, мы не инициализировали здесь никаких значений по умолчанию, поэтому наш контекст в настоящее время undefined
. Примером значения контекста аутентификации может быть {loading: false, userToken: 'abcd}
Файл AuthState.js содержит нашу логику Context API и их значения состояния. Функции, написанные здесь, можно вызывать из любого места в нашем приложении, и когда они обновляют значения в состоянии, оно также обновляется глобально.
Во-первых, давайте внесем в этот файл все импорты, которые нам понадобятся:
контекст > AuthContext > AuthState.js
import React, { useState } from 'react'; import AuthContext from './AuthContext'; import AsyncStorage from '@react-native-community/async-storage';
Мы импортировали useState()
из ReactJS для хранения наших состояний, мы импортировали файл AuthContext , который мы создали выше, потому что именно здесь инициализируется наш пустой контекст для аутентификации, и нам нужно будет использовать его, как вы увидите позже, пока мы продвигаемся. , наконец, мы импортируем пакет AsyncStorage
(аналогичный localStorage для Интернета).
AsyncStorage
— это API React Native, который позволяет сохранять данные в автономном режиме на устройстве в приложении React Native.
... const AuthState = (props) => { const [userToken, setUserToken] = useState(null); const [isLoading, setIsLoading] = useState(true); const onAuthentication = async() => { const USER_TOKEN = "drix1123q2" await AsyncStorage.setItem('user-token', USER_TOKEN); setUserToken(USER_TOKEN); console.warn("user has been authenticated!") } return ( <AuthContext.Provider value={{ onAuthentication, }} > {props.children} </AuthContext.Provider> ) } export default AuthState;
В блоке кода выше вот что мы сделали:
Мы объявили два состояния для
userToken
иisLoading
. СостояниеuserToken
будет использоваться для хранения токена, сохраненного вAsyncStorage
, а состояниеisLoading
— для отслеживания состояния загрузки (изначально установлено значениеtrue
). Мы узнаем больше об использовании этих двух состояний по ходу дела.Затем мы написали нашу
onAuthentication()
. Эта функция представляет собойasync
функцию, которая вызывается при нажатии кнопки входа в файлwelcomeScreen.jsx
. Эта функция будет вызываться только в том случае, если адрес электронной почты и пароль, предоставленные пользователем, совпадают с правильным объектом сведений о пользователе, который мы предоставили. Обычно во время аутентификации происходит токен, который создается для пользователя после того, как пользователь аутентифицируется на бэкэнде с помощью пакета, такого как JWT, и этот токен отправляется во внешний интерфейс. Поскольку мы не будем вдаваться во все это в этом руководстве, мы создали статический токен и сохранили его в переменной с именемUSER_TOKEN
.Затем мы используем ключевое слово
await
, чтобы установить для нашего пользовательского токена значение AsyncStorage с именемuser-token
. Операторconsole.warn()
просто используется для проверки того, что все прошло правильно, вы можете отключить его, когда захотите.Наконец, мы передаем нашу функцию
onAuthenticated
как значение внутри нашего<AuthContext.Provider>
, чтобы мы могли получить доступ и вызвать функцию из любого места в нашем приложении.
экраны > preAuth > welcomeScreen.js
Сначала импортируйте useContext
из ReactJS и импортируйте AuthContext
из файла AuthContext.js
.
import React, { useState, useContext } from 'react'; import AuthContext from '../../../context/authContext/AuthContext' ...
Теперь внутри функционального компонента welcomeScreen()
воспользуемся созданным нами контекстом:
... const WelcomeScreen = () => { const { onAuthentication } = useContext(AuthContext) const onUserAuthentication = () => { if ( email !== correctAuthenticationDetails.email || password !== correctAuthenticationDetails.password ) { alert('The email or password is incorrect') return } onAuthentication() } return ( ... ) } ...
В приведенном выше блоке кода мы деструктурировали функцию onAuthentication
из нашего AuthContext
а затем вызвали ее внутри нашей onUserAuthentication()
и удалили оператор console.log()
, который был там до сих пор.
Прямо сейчас это вызовет ошибку, потому что у нас еще нет доступа к AuthContext
. Чтобы использовать AuthContext
в любом месте вашего приложения, нам нужно обернуть файл верхнего уровня в нашем приложении с помощью AuthState
(в нашем случае это файл App.js ).
Перейдите в файл App.js и замените там код на этот:
import React from 'react'; import WelcomeScreen from './views/screens/preAuthScreens/welcomeScreen'; import AuthState from './context/authContext/AuthState' export default function App() { return ( <AuthState> <WelcomeScreen /> </AuthState> ); }
Мы зашли так далеко, и мы закончили с этим разделом. Прежде чем мы перейдем к следующему разделу, где мы настроим нашу маршрутизацию, давайте создадим новый экран. Экран, который мы собираемся создать, будет файлом HomeScreen.js , который должен появиться только после успешной аутентификации.
Перейдите по ссылке: экраны > postAuth .
Создайте новый файл с именем HomeScreen.js . Вот код файла HomeScreen.js :
экраны > postAuth > HomeScreen.js
import React from 'react'; import { View, Text, Button, StyleSheet } from 'react-native'; const HomeScreen = () => { const onLogout = () => { console.warn("Logout button cliked") } return ( <View style={styles.container}> <Text>Now you're authenticated! Welcome!</Text> <Button title="LOG OUT" onPress={onLogout} /> </View> ) } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#fff', alignItems: 'center', justifyContent: 'center', }, }) export default HomeScreen
На данный момент кнопка выхода имеет фиктивный оператор console.log()
. Позже мы создадим функцию выхода из системы и передадим ее на экран из нашего контекста.
Настройка наших маршрутов
Нам нужно создать три (3) файла в нашей навигационной папке:
- postAuthNavigator.js ,
- preAuthNavigator.js ,
- AppNavigator.js .
Создав эти три файла, перейдите к только что созданному файлу preAuthNaviagtor.js и напишите следующее:
навигация > preAuthNavigator.js
import React from "react"; import { createStackNavigator } from "@react-navigation/stack"; import WelcomeScreen from "../screens/preAuthScreens/welcomeScreen"; const PreAuthNavigator = () => { const { Navigator, Screen } = createStackNavigator(); return ( <Navigator initialRouteName="Welcome"> <Screen name="Welcome" component={WelcomeScreen} /> </Navigator> ) } export default PreAuthNavigator;
В файле выше вот что мы сделали:
- Мы импортировали
createStackNavigator
из@react-navigation/stack
который используем для навигации по стеку.createStackNavigator
Предоставляет вашему приложению способ перехода между экранами, где каждый новый экран помещается поверх стека. По умолчанию навигатор стека настроен на знакомый внешний вид iOS и Android: новые экраны появляются справа на iOS и исчезают снизу на Android. Нажмите здесь, если хотите узнать больше о навигаторе стека в React Native. - Мы деструктурировали
Navigator
иScreen
изcreateStackNavigator()
. - В нашем операторе return мы создали нашу навигацию с помощью
<Navigator/>
и создали наш экран с помощью<Screen/>
. это означает, что если бы у нас было несколько экранов, к которым можно получить доступ до аутентификации, у нас будет несколько тегов<Screen/>
, представляющих их здесь. - Наконец, мы экспортируем наш компонент
PreAuthNavigator
.
Давайте сделаем то же самое для файла postAuthNavigator.js
.
навигация > postAuthNavigator.js
import React from "react"; import { createStackNavigator } from "@react-navigation/stack"; import HomeScreen from "../screens/postAuthScreens/HomeScreen"; const PostAuthNavigator = () => { const { Navigator, Screen} = createStackNavigator(); return ( <Navigator initialRouteName="Home"> <Screen name="Home" component={HomeScreen} /> </Navigator> ) } export default PostAuthNavigator;
Как видно из приведенного выше кода, единственная разница между preAuthNavigator.js и postAuthNavigator.js заключается в отображаемом экране. В то время как первый занимает WelcomeScreen
, postAuthNavigator.js принимает HomeScreen
.
Чтобы создать наш AppNavigator.js , нам нужно создать несколько вещей.
Поскольку AppNavigator.js — это место, где мы будем переключаться и проверять, какой маршрут будет доступен для доступа пользователя, нам нужно несколько экранов, чтобы это работало правильно, давайте наметим то, что нам нужно создать в первую очередь:
- TransitionScreen.js
Пока приложение решает, какую навигацию оно собирается монтировать, мы хотим, чтобы отображался экран перехода. Как правило, экран перехода представляет собой счетчик загрузки или любую другую пользовательскую анимацию, выбранную для приложения, но в нашем случае мы будем использовать базовый<Text/>
для отображенияloading…
. -
checkAuthenticationStatus()
Эту функцию мы будем вызывать для проверки статуса аутентификации, который определит, какой навигационный стек будет смонтирован. Мы создадим эту функцию в нашем контексте и будем использовать ее в Appnavigator.js .
Теперь давайте продолжим и создадим наш файл TransitionScreen.js .
экраны > TransitionScreen.js
import React from 'react'; import { Text, View } from 'react-native'; const TransitionScreen = () => { return ( <View> <Text>Loading...</Text> </View> ) } export default TransitionScreen
Наш экран перехода — это просто простой экран, который показывает загрузку текста. Мы увидим, где это использовать, в этой статье.
Далее давайте перейдем к нашему AuthState.js и напишем наш checkAuthenticationStatus()
:
контекст > authContext > AuthState.js
import React, { useState, useEffect } from 'react'; import AuthContext from './AuthContext'; import AsyncStorage from '@react-native-community/async-storage'; const AuthState = (props) => { const [userToken, setUserToken] = useState(null); const [isLoading, setIsLoading] = useState(true); ... useEffect(() => { checkAuthenticationStatus() }, []) const checkAuthenticationStatus = async () => { try { const returnedToken = await AsyncStorage.getItem('user-toke n'); setUserToken(returnedToken); console.warn('User token set to the state value) } catch(err){ console.warn(`Here's the error that occured while retrievin g token: ${err}`) } setIsLoading(false) } const onAuthentication = async() => { ... } return ( <AuthContext.Provider value={{ onAuthentication, userToken, isLoading, }} > {props.children} </AuthContext.Provider> ) } export default AuthState;
В приведенном выше блоке кода мы написали функцию checkAuthenticationStatus()
. В нашей функции вот что мы делаем:
- Мы использовали ключевое слово
await
, чтобы получить наш токен изAsyncStorage
. СAsyncStorage
, если маркер не предоставлен, он возвращаетnull
. Наше начальное состояниеuserToken
также имеет значениеnull
. - Мы используем
setUserToken
, чтобы установить возвращаемое изAsyncStorage
значение в качестве новогоuserToken
. Если возвращаемое значение равноnull
, это означает, что нашuserToken
остаетсяnull
. - После блока
try{}…catch(){}
мы устанавливаем дляisLoading
значение false, поскольку функция проверки статуса аутентификации завершена. Нам понадобится значениеisLoading
, чтобы узнать, должны ли мы по-прежнему отображатьTransitionScreen
или нет. Стоит подумать об установке ошибки, если при получении токена возникает ошибка, чтобы мы могли показать пользователю кнопку «Повторить попытку» или «Попробовать еще раз» при обнаружении ошибки. - Всякий раз, когда
AuthState
монтируется, мы хотим проверить статус аутентификации, поэтому для этого мы используемuseEffect()
ReactJS. Мы вызываем нашуcheckAuthenticationStatus()
внутриuseEffect()
и устанавливаем значениеisLoading
вfalse
, когда это делается. - Наконец, мы добавляем наши состояния к нашим значениям
<AuthContext.Provider/>
, чтобы мы могли получить к ним доступ из любого места в нашем приложении, охваченном Context API.
Теперь, когда у нас есть наша функция, пришло время вернуться к нашему AppNavigator.js и написать код для монтирования определенного навигатора стека на основе статуса аутентификации:
навигация > AppNavigator.js
Во-первых, мы импортируем все, что нам нужно для нашего AppNavigator.js .
import React, { useEffect, useContext } from "react"; import PreAuthNavigator from "./preAuthNavigator"; import PostAuthNavigator from "./postAuthNavigator"; import { NavigationContainer } from "@react-navigation/native" import { createStackNavigator } from "@react-navigation/stack"; import AuthContext from "../../context/authContext/AuthContext"; import TransitionScreen from "../screens/TransitionScreen";
Теперь, когда у нас есть все импортируемые данные, давайте создадим AppNavigator()
.
... const AppNavigator = () => { } export default AppNavigator
Теперь мы приступим к написанию содержимого нашей AppNavigator()
:
import React, { useState, useEffect, useContext } from "react"; import PreAuthNavigator from "./preAuthNavigator"; import PostAuthNavigator from "./postAuthNavigator"; import { NavigationContainer } from "@react-navigation/native" import { createStackNavigator } from "@react-navigation/stack"; import AuthContext from "../../context/authContext/AuthContext"; import TransitionScreen from "../screens/transition"; const AppNavigator = () => { const { Navigator, Screen } = createStackNavigator(); const authContext = useContext(AuthContext); const { userToken, isLoading } = authContext; if(isLoading) { return <TransitionScreen /> } return ( <NavigationContainer> <Navigator> { userToken == null ? ( <Screen name="PreAuth" component={PreAuthNavigator} options={{ header: () => null }} /> ) : ( <Screen name="PostAuth" component={PostAuthNavigator} options={{ header: () => null }} /> ) } </Navigator> </NavigationContainer> ) } export default AppNavigator
В приведенном выше блоке кода показано, что мы сделали:
- Мы создали навигатор стека и деструктурировали из него
Navigator
иScreen
. - Мы импортировали
userToken
иisLoading
из нашегоAuthContext
- Когда
AuthState
монтируется, в хуке useEffecct вызываетсяuseEffecct
checkAuthenticationStatus()
. Мы используем операторif
, чтобы проверить, является лиisLoading
true
, если этоtrue
, то экран, который мы возвращаем, является нашим<TransitionScreen />
, который мы создали ранее, потому чтоcheckAuthenticationStatus()
еще не завершена. - Как только наш
checkAuthenticationStatus()
завершен, дляisLoading
устанавливается значениеfalse
, и мы возвращаем наши основные компоненты навигации. -
NavigationContainer
был импортирован из@react-navigation/native
. Он используется только один раз в основном навигаторе верхнего уровня. Обратите внимание, что мы не используем это в preAuthNavigator.js или postAuthNavigator.js. - В нашем
AppNavigator()
мы по-прежнему создаем навигатор стека. ЕслиuserToken
полученный из нашего Context API, имеет значениеnull
, мы монтируемPreAuthNavigator
, если его значение другое (имеется в виду, чтоAsyncStorage.getItem()
вcheckAuthenticationStatus()
возвращает фактическое значение), то мы монтируемPostAuthNavigator
. Наш условный рендеринг выполняется с помощью тернарного оператора.
Теперь мы настроили наш AppNavigator.js . Далее нам нужно передать наш AppNavigator
в наш файл App.js.
Давайте передадим наш AppNavigator
в файл App.js :
App.js
... import AppNavigator from './views/navigation/AppNavigator'; ... return ( <AuthState> <AppNavigator /> </AuthState> );
Давайте теперь посмотрим, как выглядит наше приложение на данный момент:
Вот что происходит, когда вы указываете неверные учетные данные при попытке входа в систему:
Добавление функции выхода из системы
На этом наш процесс аутентификации и выбора маршрута завершен. Единственное, что осталось для нашего приложения, это добавить функцию выхода из системы.
Кнопка выхода находится в файле HomeScreen.js . Мы передали функцию onLogout()
в атрибут onPress
кнопки. На данный момент у нас есть простой оператор console.log()
в нашей функции, но через некоторое время это изменится.
Теперь давайте перейдем к нашему AuthState.js и напишем функцию выхода из системы. Эта функция просто очищает AsyncStorage
где сохранен токен пользователя.
контекст > authContext > AuthState.js
... const AuthState = (props) => { ... const userSignout = async() => { await AsyncStorage.removeItem('user-token'); setUserToken(null); } return ( ... ) } export default AuthState;
userSignout()
— это асинхронная функция, которая удаляет user-token
из нашего AsyncStorage
.
Теперь нам нужно вызывать userSignout()
в нашем HomeScreen.js каждый раз, когда нажимается кнопка выхода.
Давайте перейдем к нашему HomeScreen.js и используем userSignout()
из нашего AuthContext
.
экраны > postAuthScreens > HomeScreen.js
import React, { useContext } from 'react'; import { View, Text, Button, StyleSheet } from 'react-native'; import AuthContext from '../../../context/authContext/AuthContext' const HomeScreen = () => { const { userSignout } = useContext(AuthContext) const onLogout = () => { userSignout() } return ( <View style={styles.container}> <Text>Now you're authenticated! Welcome!</Text> <Button title="LOG OUT" onPress={onLogout} /> </View> ) } ...
В приведенном выше блоке кода мы импортировали хук useContext
из ReactJS, а затем импортировали наш AuthContext. Затем мы деструктурировали функцию userSignout
из нашего AuthContext
и эта userSignout()
вызывается в нашей onLogout()
.
Теперь всякий раз, когда нажимается наша кнопка выхода, токен пользователя в нашем AsyncStorage
очищается.
Вуаля! весь наш процесс завершен.
Вот что происходит, когда вы нажимаете кнопку «Назад» после входа в систему:
Вот что происходит, когда вы нажимаете кнопку «Назад» после выхода из системы:
Вот некоторые особенности поведения, которые мы замечаем при использовании этого шаблона при переключении стека навигации:
- Вы заметите, что нам нигде не нужно было использовать
navigation.navigate()
илиnavigation.push()
для перехода на другой маршрут после входа в систему. Как только наше состояние обновляется токеном пользователя, отображаемый стек навигации автоматически изменяется. - Нажатие кнопки «Назад» на вашем устройстве после успешного входа в систему не вернет вас на страницу входа, а полностью закроет приложение. Такое поведение важно, потому что вы не хотите, чтобы пользователь мог вернуться на страницу входа, если он не выйдет из приложения. То же самое относится и к выходу из системы — после выхода пользователь не может использовать кнопку «Назад», чтобы вернуться на экран
HomeScreen
, вместо этого приложение закрывается.
Заключение
Во многих приложениях аутентификация является одной из наиболее важных частей, поскольку она подтверждает, что человек, пытающийся получить доступ к защищенному контенту, имеет право на доступ к информации. Научиться делать это правильно — важный шаг в создании отличного, интуитивно понятного и простого в использовании/навигации приложения.
Основываясь на этом коде, вот несколько вещей, которые вы можете добавить:
- Проверка формы для проверки полей ввода. Ознакомьтесь с проверкой формы React Native с помощью Formik и Yup.
- Аутентификация Firebase для интеграции аутентификации с Gmail, Github, Facebook, Twitter или вашим пользовательским интерфейсом. Проверьте React Native Firebase.
- Концепции кода для дизайнеров: аутентификация и авторизация.
Вот также некоторые важные ресурсы, которые я нашел, которые расскажут вам больше об аутентификации, безопасности и о том, как это сделать правильно:
Ресурсы
- React Native: объяснение процесса аутентификации пользователя
- 10 лучших практик безопасности React
- Методы аутентификации, которые могут предотвратить следующее нарушение
- Посмотреть живую сборку/превью нашего приложения можно здесь;
- Посмотреть проект на GitHub.