Obsługa montowania i odłączania tras nawigacyjnych w React Native
Opublikowany: 2022-03-10W tym artykule omówimy montowanie i odmontowywanie tras nawigacyjnych w React Native. Oczekiwane zachowanie aplikacji polega na tym, że po spełnieniu warunku uwierzytelnienia nowy zestaw tras nawigacji jest dostępny tylko dla zalogowanych użytkowników, podczas gdy inne ekrany, które były wyświetlane przed uwierzytelnieniem, są usuwane i nie można do nich powrócić, chyba że użytkownik wyloguje się z aplikacji.
Ze względów bezpieczeństwa w Twojej aplikacji chronione trasy umożliwiają wyświetlanie tylko określonych informacji/treści w aplikacji określonym użytkownikom, jednocześnie ograniczając dostęp osobom nieupoważnionym.
Będziemy współpracować z Expo nad tym projektem, ponieważ pomoże nam to skoncentrować się na bieżącym problemie, zamiast martwić się o wiele konfiguracji. Dokładnie te same kroki opisane w tym artykule można wykonać dla samej aplikacji React Native.
Aby zapoznać się z tym samouczkiem, potrzebujesz trochę znajomości JavaScript i React Native . Oto kilka ważnych rzeczy, które powinieneś już znać:
- Komponenty niestandardowe w React Native (jak tworzyć komponenty, otrzymywać, przekazywać i używać właściwości w komponencie). Czytaj więcej.
- Reaguj nawigację. Czytaj więcej.
- Stack Navigator w React Native. Czytaj więcej.
- Podstawowa znajomość komponentów React Native Core (
<View/>
,<Text/>
, itp.). Czytaj więcej. - React Native
AsyncStorage
. Czytaj więcej. - Kontekstowy interfejs API. Czytaj więcej.
Konfiguracja projektu i uwierzytelnianie podstawowe
Jeśli jesteś nowy w używaniu expo i nie wiesz, jak zainstalować expo, odwiedź oficjalną dokumentację. Po zakończeniu instalacji przejdź dalej, aby zainicjować nowy projekt React Native z expo z naszego wiersza poleceń:
expo init navigation-project
Zostaną wyświetlone opcje umożliwiające wybór sposobu, w jaki ma wyglądać podstawowa konfiguracja:
W naszym przypadku wybierzmy pierwszą opcję, aby ustawić nasz projekt jako pusty dokument. Teraz poczekaj, aż instalacja zależności JavaScript zostanie zakończona.
Po skonfigurowaniu naszej aplikacji możemy zmienić nasz katalog na nasz nowy katalog projektu i otworzyć go w ulubionym edytorze kodu. Musimy zainstalować bibliotekę, której będziemy używać dla AsyncStorage
i naszych bibliotek nawigacyjnych. W swoim katalogu folderów w terminalu wklej powyższe polecenie i wybierz szablon ( blank
zadziała), aby zainstalować nasze zależności projektu.
Przyjrzyjmy się, do czego służy każda z tych zależności:
- @react-native-community/async-storage
Podobnie jak localStorage w sieci, jest to interfejs API React Native do utrwalania danych na urządzeniu w parach klucz-wartość. - @react-native-community/widok-maskowany, ekrany natywne reakcji, uchwyt-gestu-react-native
Te zależności to podstawowe narzędzia używane przez większość nawigatorów do tworzenia struktury nawigacji w aplikacji. (Przeczytaj więcej w Rozpoczęcie pracy z nawigacją React Native.) - @react-navigation/native
To jest zależność nawigacji React Native. - @react-nawigacja/stos
Jest to zależność nawigacji stosu w 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
Aby uruchomić aplikację, użyj expo start
z katalogu aplikacji w swoim terminalu. Po uruchomieniu aplikacji możesz użyć aplikacji expo z telefonu komórkowego, aby zeskanować kod kreskowy i wyświetlić aplikację, a jeśli masz emulator Androida/symulator IOS, możesz otworzyć aplikację za ich pośrednictwem z narzędzia programisty expo, które otwiera się w przeglądarce po uruchomieniu aplikacji expo. W przypadku przykładów obrazów w tym artykule użyjemy Genymotions, aby zobaczyć nasz wynik. Oto jak będzie wyglądał nasz końcowy wynik w Genymotions:
Struktury folderów
Stwórzmy naszą strukturę folderów od samego początku, aby łatwiej było nam z nią pracować:
Najpierw potrzebujemy dwóch folderów:
- kontekst
Ten folder będzie zawierał kontekst dla całej naszej aplikacji, ponieważ będziemy pracować z Context API dla globalnego zarządzania stanem. - wyświetlenia
Ten folder będzie zawierał zarówno folder nawigacyjny, jak i widoki dla różnych ekranów.
Śmiało i utwórz dwa foldery w katalogu projektu.
Wewnątrz folderu kontekstowego utwórz folder o nazwie authContext i utwórz dwa pliki wewnątrz folderu authContext :
- AuthContext.js ,
- AuthState.js .
Pliki te będą nam potrzebne, gdy zaczniemy pracować z Context API.
Teraz przejdź do folderu widoków , który utworzyliśmy i utwórz w nim jeszcze dwa foldery, a mianowicie:
- nawigacja ,
- ekrany .
Teraz jeszcze nie skończyliśmy, w folderze screens utwórz te dwa kolejne foldery:
- postAuthScreen ,
- PreAuthScreen .
Jeśli prawidłowo postępowałeś zgodnie z konfiguracją folderów, tak powinna wyglądać obecnie struktura folderów:
Tworzenie naszego pierwszego ekranu
Teraz utwórzmy nasz pierwszy ekran i nazwijmy go welcomeScreen.js w folderze preAuthScreens .
preAuthScreens > welcomeScreen.js
Oto zawartość naszego pliku 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
Oto, co zrobiliśmy w powyższym bloku kodu:
Najpierw zaimportowaliśmy potrzebne nam rzeczy z biblioteki React Native, a mianowicie View
, Text
, Button
, TextInput
. Następnie stworzyliśmy nasz funkcjonalny komponent WelcomeScreen
.
Zauważysz, że zaimportowaliśmy StyleSheet
stylów z React Native i użyliśmy go do zdefiniowania stylów naszego nagłówka, a także naszego <TextInput />
.
Na koniec eksportujemy komponent WelcomeScreen
na dole kodu.
Teraz, gdy już z tym skończyliśmy, sprawmy, aby ten komponent działał zgodnie z oczekiwaniami, używając zaczepu useState
do przechowywania wartości danych wejściowych i aktualizowania ich stanów za każdym razem, gdy nastąpi zmiana w polach wejściowych. Wprowadzimy również import useCallback
z Reacta, ponieważ będziemy go później potrzebować do przechowywania funkcji.
Po pierwsze, gdy wciąż jesteśmy w komponencie WelcomeScreen
, musimy zaimportować useState
i useCallback
z Reacta.
import React, { useState, useCallback } from 'react';
Teraz w komponencie funkcjonalnym WelcomeScreen
stwórzmy dwa stany odpowiednio dla adresu e-mail i hasła:
... const WelcomeScreen = () => { const [email, setEmail] = useState('') const [password, setPassword] = useState('') return ( ... ) } ...
Następnie musimy zmodyfikować nasze pola <TextInput />
tak, aby pobierały ich wartość z odpowiednich stanów i aktualizowały swój stan, gdy wartość danych wejściowych jest aktualizowana:
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> ) } ...
W powyższym kodzie, oto co zrobiliśmy:
- Ustaliliśmy, że
value
każdego z danych wejściowych tekstu wskazuje na ich odpowiedni stan. - Dodaliśmy procedurę obsługi
onChangeText
do naszych danych wejściowych tekstu. To uruchamia się za każdym razem, gdy nowa wartość zostanie wprowadzona lub usunięta z pól wejściowych. - Wywołaliśmy naszą funkcję
onInputChange
, która przyjmuje dwa argumenty:- Bieżąca
value
jest dostarczana przez procedurę obsługionChangeText
. - Seter stanu, który ma zostać zaktualizowany (dla pierwszego pola wejściowego przekazujemy
setEmail
a dla drugiegosetPassword
. - Na koniec piszemy naszą funkcję
onInputChange
, a nasza funkcja robi tylko jedną rzecz: aktualizuje odpowiednie stany o nową wartość.
- Bieżąca
Następną rzeczą, nad którą musimy popracować, jest funkcja onUserAuthentication()
, która jest wywoływana za każdym razem, gdy zostanie kliknięty przycisk przesyłania formularza.
W idealnym przypadku użytkownik musi już utworzyć konto, a logowanie będzie wymagało pewnego rodzaju logiki zaplecza, aby sprawdzić, czy użytkownik istnieje, a następnie przypisać mu token. W naszym przypadku, ponieważ nie używamy żadnego zaplecza, utworzymy obiekt zawierający prawidłowe dane logowania użytkownika, a następnie uwierzytelnimy użytkownika tylko wtedy, gdy wprowadzone przez niego wartości będą zgodne z naszymi stałymi wartościami z obiektu logowania adresu e- email
i password
, które będziemy Stwórz.
Oto kod, którego potrzebujemy, aby to zrobić:
... 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 ( ... ) } ...
Jedną z pierwszych rzeczy, które zauważysz w powyższym kodzie, jest to, że zdefiniowaliśmy correctAuthenticationDetails
(jest to obiekt, który przechowuje prawidłowe dane logowania, jakich oczekujemy od użytkownika) poza składnikiem funkcjonalnym WelcomeScreen()
.
Następnie napisaliśmy zawartość funkcji onUserAuthentication()
i użyliśmy instrukcji warunkowej, aby sprawdzić, czy email
lub password
przechowywane w odpowiednich stanach nie zgadza się z tym, który podaliśmy w naszym obiekcie.
Jeśli chcesz zobaczyć, co zrobiliśmy do tej pory, zaimportuj komponent WelcomeScreen do swojego App.js w następujący sposób:
Otwórz plik App.js i umieść go, zastępując cały kod następującym:
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> ); }
Przyglądając się uważnie powyższemu kodowi, zobaczysz, że zaimportowaliśmy składnik WelcomeScreen , a następnie użyliśmy go w funkcji App()
.
Oto jak wygląda wynik naszego WelcomeScreen
:
Teraz, gdy skończyliśmy budować komponent WelcomeScreen , przejdźmy dalej i zacznijmy pracować z Context API do zarządzania naszym globalnym stanem.
Dlaczego API kontekstowe?
Korzystając z Context API, nie musimy instalować żadnej dodatkowej biblioteki w ReactJS, konfiguracja jest mniej stresująca i jest jednym z najpopularniejszych sposobów obsługi stanu globalnego w ReactJS. W przypadku lekkiego zarządzania stanem jest to dobry wybór.
Tworzenie naszego kontekstu
Jeśli pamiętasz, wcześniej utworzyliśmy folder kontekstowy i utworzyliśmy w nim podfolder o nazwie authContext .
Przejdźmy teraz do pliku AuthContext.js w folderze authContext i stwórzmy nasz kontekst:
kontekst > authContext > AuthContext.js
import React, { createContext } from 'react'; const AuthContext = createContext(); export default AuthContext;
AuthContext
, który właśnie utworzyliśmy, przechowuje wartość stanu loading
i wartości stanu userToken
. Obecnie w createContext
, które zadeklarowaliśmy w powyższym bloku kodu, nie zainicjowaliśmy tutaj żadnych wartości domyślnych, więc nasz kontekst jest obecnie undefined
. Przykładową wartością kontekstu uwierzytelniania może być {loading: false, userToken: 'abcd}
Plik AuthState.js zawiera naszą logikę Context API i ich wartości stanów. Napisane tutaj funkcje można wywoływać z dowolnego miejsca w naszej aplikacji, a gdy aktualizują wartości w stanie, są one również aktualizowane globalnie.
Najpierw wprowadźmy wszystkie importy, których będziemy potrzebować w tym pliku:
kontekst > AuthContext > AuthState.js
import React, { useState } from 'react'; import AuthContext from './AuthContext'; import AsyncStorage from '@react-native-community/async-storage';
Zaimportowaliśmy hak useState()
z ReactJS do przechowywania naszych stanów, zaimportowaliśmy plik AuthContext , który utworzyliśmy powyżej, ponieważ w tym miejscu inicjowany jest nasz pusty kontekst do uwierzytelniania i będziemy musieli go użyć, jak zobaczysz później, w miarę postępów , na koniec importujemy pakiet AsyncStorage
(podobnie jak localStorage dla sieci).
AsyncStorage
to interfejs API React Native, który umożliwia utrwalanie danych w trybie offline na urządzeniu w aplikacji 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;
W powyższym bloku kodu oto, co zrobiliśmy:
Zadeklarowaliśmy dwa stany dla
userToken
iisLoading
. StanuserToken
będzie używany do przechowywania tokena zapisanego wAsyncStorage
, natomiast stanisLoading
będzie używany do śledzenia stanu ładowania (początkowo jest ustawiony natrue
). W dalszej części dowiemy się więcej o wykorzystaniu tych dwóch stanów.Następnie napisaliśmy naszą funkcję
onAuthentication()
. Ta funkcja jest funkcjąasync
, która jest wywoływana po kliknięciu przycisku logowania w plikuwelcomeScreen.jsx
. Ta funkcja zostanie wywołana tylko wtedy, gdy podany przez użytkownika adres e-mail i hasło będą pasować do prawidłowego podanego przez nas obiektu szczegółów użytkownika. Zwykle to, co dzieje się podczas uwierzytelniania, polega na tym, że token jest generowany dla użytkownika po uwierzytelnieniu użytkownika na zapleczu przy użyciu pakietu takiego jak JWT, a ten token jest wysyłany do interfejsu użytkownika. Ponieważ nie zajmiemy się tym wszystkim w tym samouczku, utworzyliśmy statyczny token i trzymaliśmy go w zmiennej o nazwieUSER_TOKEN
.Następnie używamy słowa kluczowego
await
, aby ustawić nasz token użytkownika na AsyncStorage o nazwieuser-token
. Instrukcjaconsole.warn()
służy tylko do sprawdzenia, czy wszystko poszło dobrze, możesz ją zdjąć, kiedy tylko chcesz.Na koniec przekazujemy naszą funkcję
onAuthenticated
jako wartość wewnątrz naszego<AuthContext.Provider>
, dzięki czemu możemy uzyskać dostęp do funkcji i wywołać ją z dowolnego miejsca w naszej aplikacji.
ekrany > preAuth > welcomeScreen.js
Najpierw zaimportuj useContext
z ReactJS i zaimportuj AuthContext
z pliku AuthContext.js
.
import React, { useState, useContext } from 'react'; import AuthContext from '../../../context/authContext/AuthContext' ...
Teraz w komponencie funkcjonalnym welcomeScreen()
kontekstu, który stworzyliśmy:
... 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 ( ... ) } ...
W powyższym bloku kodu zdestrukturyzowaliśmy funkcję onAuthentication
z naszego AuthContext
, a następnie wywołaliśmy ją wewnątrz funkcji onUserAuthentication()
i usunęliśmy instrukcję console.log()
, która była tam wcześniej.
W tej chwili spowoduje to zgłoszenie błędu, ponieważ nie mamy jeszcze dostępu do AuthContext
. Aby użyć AuthContext
w dowolnym miejscu w aplikacji, musimy umieścić w naszej aplikacji plik najwyższego poziomu z AuthState
(w naszym przypadku jest to plik App.js ).
Przejdź do pliku App.js i zastąp tam kod następującym:
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> ); }
Zaszliśmy tak daleko i skończyliśmy z tą sekcją. Zanim przejdziemy do następnej sekcji, w której ustawimy nasz routing, utwórzmy nowy ekran. Ekranem, który zamierzamy utworzyć, będzie plik HomeScreen.js , który ma pojawić się dopiero po pomyślnym uwierzytelnieniu.
Przejdź do: screens > postAuth .
Utwórz nowy plik o nazwie HomeScreen.js . Oto kod pliku HomeScreen.js :
ekrany > 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
Na razie przycisk wylogowania ma fikcyjną instrukcję console.log()
. Później stworzymy funkcję wylogowania i przekażemy ją na ekran z naszego kontekstu.
Konfigurowanie naszych tras
Musimy utworzyć trzy (3) pliki w naszym folderze nawigacyjnym:
- postAuthNavigator.js ,
- preAuthNavigator.js ,
- AppNavigator.js .
Po utworzeniu tych trzech plików przejdź do utworzonego właśnie pliku preAuthNaviagtor.js i napisz:
nawigacja > 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;
W powyższym pliku, oto co zrobiliśmy:
- Zaimportowaliśmy
createStackNavigator
z@react-navigation/stack
, którego używamy do naszej nawigacji stosu.createStackNavigator
Umożliwia aplikacji przechodzenie między ekranami, gdzie każdy nowy ekran jest umieszczany na szczycie stosu. Domyślnie nawigator stosów jest skonfigurowany tak, aby mieć znajomy wygląd i działanie systemów iOS i Android: nowe ekrany wsuwają się od prawej w systemie iOS, wygasają od dołu w systemie Android. Kliknij tutaj, jeśli chcesz dowiedzieć się więcej o nawigatorze stosów w React Native. - Zdestrukturyzowaliśmy
Navigator
iScreen
z metodycreateStackNavigator()
. - W naszej deklaracji zwrotu stworzyliśmy naszą nawigację za pomocą
<Navigator/>
i stworzyliśmy nasz ekran za pomocą<Screen/>
. oznacza to, że gdybyśmy mieli wiele ekranów, do których można uzyskać dostęp przed uwierzytelnieniem, będziemy mieli tutaj wiele<Screen/>
reprezentujących je. - Na koniec eksportujemy nasz komponent
PreAuthNavigator
.
Zróbmy podobną rzecz dla pliku postAuthNavigator.js
.
nawigacja > 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;
Jak widać w powyższym kodzie, jedyną różnicą między preAuthNavigator.js a postAuthNavigator.js jest renderowany ekran. Podczas gdy pierwszy z nich zajmuje ekran powitalny , WelcomeScreen
zajmuje HomeScreen
główny .
Aby stworzyć nasz AppNavigator.js musimy stworzyć kilka rzeczy.
Ponieważ AppNavigator.js to miejsce, w którym będziemy przełączać się i sprawdzać, która trasa będzie dostępna dla użytkownika, potrzebujemy kilku ekranów, aby to działało poprawnie, nakreślmy rzeczy, które musimy najpierw stworzyć:
- TransitionScreen.js
Podczas gdy aplikacja decyduje, którą nawigację zamierza zamontować, chcemy, aby pojawił się ekran przejściowy. Zazwyczaj ekranem przejścia będzie spinner ładowania lub inna niestandardowa animacja wybrana dla aplikacji, ale w naszym przypadku użyjemy podstawowego tagu<Text/>
, aby wyświetlićloading…
. -
checkAuthenticationStatus()
Ta funkcja jest tym, co będziemy wywoływać, aby sprawdzić stan uwierzytelniania, który określi, który stos nawigacyjny zostanie zamontowany. Stworzymy tę funkcję w naszym kontekście i użyjemy jej w Appnavigator.js .
Teraz chodźmy dalej i stwórzmy nasz plik TransitionScreen.js .
ekrany > TransitionScreen.js
import React from 'react'; import { Text, View } from 'react-native'; const TransitionScreen = () => { return ( <View> <Text>Loading...</Text> </View> ) } export default TransitionScreen
Nasz ekran przejścia to po prostu prosty ekran, który pokazuje wczytujący się tekst. Zobaczymy, gdzie tego użyć, w dalszej części tego artykułu.
Następnie przejdźmy do naszego AuthState.js i checkAuthenticationStatus()
:
context > 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;
W powyższym bloku kodu napisaliśmy funkcję checkAuthenticationStatus()
. W naszej funkcji oto, co robimy:
- Użyliśmy słowa kluczowego
await
, aby uzyskać nasz token zAsyncStorage
. W przypadkuAsyncStorage
, jeśli nie podano tokenu, zwracanull
. Nasz początkowy stanuserToken
jest również ustawiony nanull
. - Używamy
setUserToken
, aby ustawić naszą wartość zwracaną zAsyncStorage
jako nasz nowyuserToken
. Jeśli zwrócona wartość tonull
, oznacza to, że naszuserToken
pozostajenull
. - Po bloku
try{}…catch(){}
ustawiamyisLoading
na false, ponieważ funkcja sprawdzania statusu uwierzytelniania jest zakończona. Potrzebujemy wartościisLoading
, aby wiedzieć, czy nadal powinniśmy wyświetlaćTransitionScreen
, czy nie. Warto zastanowić się nad ustawieniem błędu, jeśli wystąpi błąd podczas pobierania tokena, abyśmy mogli pokazać użytkownikowi przycisk „Ponów” lub „Spróbuj ponownie” po napotkaniu błędu. - Za każdym razem, gdy montuje się
AuthState
, chcemy sprawdzić status uwierzytelnienia, więc używamy do tego hakauseEffect()
ReactJS. Wywołujemy naszącheckAuthenticationStatus()
wewnątrzuseEffect()
i ustawiamy wartośćisLoading
nafalse
po zakończeniu. - Na koniec dodajemy nasze stany do naszych wartości
<AuthContext.Provider/>
, dzięki czemu możemy uzyskać do nich dostęp z dowolnego miejsca w naszej aplikacji objętej interfejsem Context API.
Teraz, gdy mamy już naszą funkcję, czas wrócić do naszego AppNavigator.js i napisać kod do zamontowania konkretnego nawigatora stosu na podstawie stanu uwierzytelnienia:
nawigacja > AppNavigator.js
Najpierw zaimportujemy wszystko, czego potrzebujemy do naszego 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";
Teraz, gdy mamy już wszystkie importy, utwórzmy funkcję AppNavigator()
.
... const AppNavigator = () => { } export default AppNavigator
Następnie przejdziemy do napisania zawartości naszej funkcji 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
W powyższym bloku kodu, oto zarys tego, co zrobiliśmy:
- Stworzyliśmy nawigator stosu i zdestrukturyzowaliśmy z niego
Navigator
iScreen
. - Zaimportowaliśmy
userToken
iisLoading
z naszegoAuthContext
- Gdy
AuthState
montuje się, w haczykuuseEffecct
wywoływana jest funkcjacheckAuthenticationStatus()
. Używamy instrukcjiif
, aby sprawdzić, czyisLoading
ma wartośćtrue
, jeśli jest onatrue
, zwróconym ekranem jest nasz<TransitionScreen />
, który utworzyliśmy wcześniej, ponieważ funkcjacheckAuthenticationStatus()
nie jest jeszcze ukończona. - Po zakończeniu
checkAuthenticationStatus()
isLoading
jest ustawiane nafalse
i zwracamy nasze główne komponenty nawigacyjne. -
NavigationContainer
został zaimportowany z@react-navigation/native
. Jest używany tylko raz w głównym nawigatorze najwyższego poziomu. Zauważ, że nie używamy tego w preAuthNavigator.js lub postAuthNavigator.js. - W naszej
AppNavigator()
nadal tworzymy nawigator stosu. JeśliuserToken
z naszego Context API jestnull
, montujemyPreAuthNavigator
, jeśli jego wartość jest inna (co oznacza, żeAsyncStorage.getItem()
wcheckAuthenticationStatus()
zwróciła rzeczywistą wartość), montujemyPostAuthNavigator
. Nasze renderowanie warunkowe odbywa się za pomocą operatora trójargumentowego.
Teraz skonfigurowaliśmy nasz AppNavigator.js . Następnie musimy przekazać nasz AppNavigator
do naszego pliku App.js.
Przekażmy nasz AppNavigator
do pliku App.js :
App.js
... import AppNavigator from './views/navigation/AppNavigator'; ... return ( <AuthState> <AppNavigator /> </AuthState> );
Zobaczmy teraz, jak obecnie wygląda nasza aplikacja:
Oto, co się dzieje, gdy podczas próby logowania podasz nieprawidłowe dane uwierzytelniające:
Dodawanie funkcji wylogowania
W tym momencie nasz proces uwierzytelniania i wyboru trasy jest zakończony. Jedyne, co pozostało naszej aplikacji, to dodanie funkcji wylogowania.
Przycisk wylogowania znajduje się w pliku HomeScreen.js . Do atrybutu onPress
przycisku przekazaliśmy funkcję onLogout()
. Na razie w naszej funkcji mamy prostą instrukcję console.log()
, ale za chwilę to się zmieni.
Przejdźmy teraz do naszego AuthState.js i napiszmy funkcję wylogowania. Ta funkcja po prostu czyści AsyncStorage
, w którym jest zapisany token użytkownika.
context > authContext > AuthState.js
... const AuthState = (props) => { ... const userSignout = async() => { await AsyncStorage.removeItem('user-token'); setUserToken(null); } return ( ... ) } export default AuthState;
userSignout()
to funkcja asynchroniczna, która usuwa user-token
z naszego AsyncStorage
.
Teraz musimy wywołać funkcję userSignout()
w naszym HomeScreen.js za każdym razem, gdy klikniemy przycisk wylogowania.
Przejdźmy do naszego HomeScreen.js i userSignout()
z naszego AuthContext
.
ekrany > 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> ) } ...
W powyższym bloku kodu zaimportowaliśmy useContext
z ReactJS, a następnie zaimportowaliśmy nasz AuthContext. Następnie zdestrukturyzowaliśmy funkcję userSignout
z naszego AuthContext
i ta userSignout()
jest wywoływana w naszej funkcji onLogout()
.
Teraz za każdym razem, gdy klikniesz nasz przycisk wylogowania, token użytkownika w naszym AsyncStorage
zostanie wyczyszczony.
Voila! cały nasz proces jest zakończony.
Oto, co się dzieje po naciśnięciu przycisku Wstecz po zalogowaniu:
Oto, co się dzieje po naciśnięciu przycisku Wstecz po wylogowaniu:
Oto kilka różnych zachowań, które zauważamy podczas używania tego wzorca w naszym przełączaniu stosu nawigacyjnego:
- Zauważysz, że nigdzie nie musieliśmy korzystać z
navigation.navigate()
lubnavigation.push()
, aby przejść do innej trasy po zalogowaniu. Gdy nasz stan zostanie zaktualizowany tokenem użytkownika, renderowany stos nawigacji jest automatycznie zmieniany. - Naciśnięcie przycisku wstecz na urządzeniu po pomyślnym zalogowaniu nie spowoduje powrotu do strony logowania, zamiast tego całkowicie zamyka aplikację. To zachowanie jest ważne, ponieważ nie chcesz, aby użytkownik mógł wrócić do strony logowania, z wyjątkiem wylogowania się z aplikacji. To samo dotyczy wylogowania — gdy użytkownik się wyloguje, nie może użyć przycisku Wstecz, aby powrócić do ekranu
HomeScreen
, ale zamiast tego aplikacja się zamyka.
Wniosek
W wielu aplikacjach uwierzytelnianie jest jedną z najważniejszych części, ponieważ potwierdza, że osoba próbująca uzyskać dostęp do chronionych treści ma prawo dostępu do informacji. Nauczenie się, jak zrobić to dobrze, jest ważnym krokiem w budowaniu świetnej, intuicyjnej i łatwej w użyciu/nawigacji aplikacji.
Opierając się na tym kodzie, oto kilka rzeczy, które warto dodać:
- Walidacja formularza do walidacji pól wejściowych. Sprawdź walidację formularzy React Native za pomocą Formik i Yup.
- Uwierzytelnianie Firebase do integracji uwierzytelniania z Gmailem, Github, Facebookiem, Twitterem lub niestandardowym interfejsem. Sprawdź React Native Firebase.
- Koncepcje kodu dla projektantów: Uwierzytelnianie i Autoryzacja.
Oto kilka ważnych zasobów, które znalazłem, które pozwolą ci dowiedzieć się więcej na temat uwierzytelniania, bezpieczeństwa i tego, jak zrobić to dobrze:
Zasoby
- React Native: Objaśnienie procesu uwierzytelniania użytkownika
- 10 najlepszych praktyk w zakresie bezpieczeństwa React
- Metody uwierzytelniania, które mogą zapobiec kolejnym naruszeniom
- Zobacz kompilację/podgląd na żywo naszej aplikacji tutaj;
- Zobacz projekt na GitHub.