Gestione del montaggio e smontaggio di rotte di navigazione in React Native
Pubblicato: 2022-03-10In questo articolo, analizzeremo il montaggio e lo smontaggio delle rotte di navigazione in React Native. Un comportamento previsto della tua app è che una volta soddisfatta la condizione di autenticazione, un nuovo set di percorsi di navigazione è disponibile solo per gli utenti che hanno effettuato l'accesso, mentre le altre schermate visualizzate prima dell'autenticazione vengono rimosse e non possono essere ripristinate a meno che il l'utente si disconnette dall'applicazione.
Per la sicurezza nella tua app, i percorsi protetti ti offrono un modo per mostrare determinate informazioni/contenuti sulla tua app solo a utenti specifici, limitando l'accesso a persone non autorizzate.
Lavoreremo con Expo per questo progetto perché ci aiuterà a concentrarci sul problema in questione invece di preoccuparci di molti allestimenti. Gli stessi identici passaggi in questo articolo possono essere seguiti per un'applicazione React Native nuda.
È necessaria una certa familiarità con JavaScript e React Native per seguire questo tutorial. Ecco alcune cose importanti che dovresti già conoscere:
- Componenti personalizzati in React Native (come creare componenti, ricevere, passare e utilizzare oggetti di scena in un componente). Per saperne di più.
- Navigazione di reazione. Per saperne di più.
- Stack Navigator in React Native. Per saperne di più.
- Conoscenza di base dei componenti React Native Core (
<View/>
,<Text/>
, ecc.). Per saperne di più. - Reagire
AsyncStorage
nativo. Per saperne di più. - API di contesto. Per saperne di più.
Configurazione del progetto e autenticazione di base
Se non conosci l'utilizzo di expo e non sai come installare expo, visita la documentazione ufficiale. Una volta completata l'installazione, vai avanti per inizializzare un nuovo progetto React Native con expo dal nostro prompt dei comandi:
expo init navigation-project
Ti verranno presentate alcune opzioni per scegliere come desideri che sia la configurazione di base:
Nel nostro caso, selezioniamo la prima opzione per impostare il nostro progetto come documento vuoto. Ora attendi fino al completamento dell'installazione delle dipendenze JavaScript.
Una volta configurata la nostra app, possiamo cambiare la nostra directory nella nostra nuova directory di progetto e aprirla nel tuo editor di codice preferito. Dobbiamo installare la libreria che useremo per AsyncStorage
e le nostre librerie di navigazione. All'interno della directory della tua cartella nel tuo terminale, incolla il comando sopra e scegli un modello ( blank
funzionerebbe) per installare le dipendenze del nostro progetto.
Diamo un'occhiata a cosa serve ciascuna di queste dipendenze:
- @react-native-community/async-storage
Come localStorage sul Web, è un'API React Native per la persistenza dei dati su un dispositivo in coppie chiave-valore. - @react-native-community/masked-view, react-native-screens, react-native-gesture-handle
Queste dipendenze sono utilità di base utilizzate dalla maggior parte dei navigatori per creare la struttura di navigazione nell'app. (Leggi di più in Introduzione alla navigazione React Native.) - @react-navigation/nativo
Questa è la dipendenza per la navigazione React Native. - @reagire-navigazione/stack
Questa è la dipendenza per la navigazione dello stack in 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
Per avviare l'applicazione usa expo start
dalla directory dell'app nel tuo terminale. Una volta avviata l'app, puoi utilizzare l'app expo dal tuo telefono cellulare per scansionare il codice a barre e visualizzare l'applicazione, oppure se disponi di un emulatore Android/simulatore IOS, puoi aprire l'app tramite lo strumento di sviluppo expo che si apre nel tuo browser quando avvii un'applicazione Expo. Per gli esempi di immagini in questo articolo, useremo Genymotions per vedere il nostro risultato. Ecco come apparirà il nostro risultato finale in Genymotions:
Strutture di cartelle
Creiamo la nostra struttura di cartelle dall'inizio in modo che sia più facile lavorarci mentre procediamo:
Abbiamo bisogno prima di due cartelle:
- contesto
Questa cartella conterrà il contesto per l'intera nostra applicazione poiché lavoreremo con l'API Context per la gestione globale dello stato. - visualizzazioni
Questa cartella conterrà sia la cartella di navigazione che le viste per le diverse schermate.
Vai avanti e crea le due cartelle nella directory del tuo progetto.
All'interno della cartella di contesto, crea una cartella chiamata authContext e crea due file all'interno della cartella authContext :
- AuthContext.js ,
- AuthState.js .
Avremo bisogno di questi file quando inizieremo a lavorare con Context API.
Ora vai alla cartella delle viste che abbiamo creato e crea altre due cartelle al suo interno, ovvero:
- navigazione ,
- schermi .
Ora, non abbiamo ancora finito, all'interno della cartella schermate , crea queste altre due cartelle:
- postAuthScreens ,
- preAuthScreens .
Se hai seguito correttamente l'impostazione della cartella, ecco come dovrebbe apparire la struttura della tua cartella al momento:
Creazione del nostro primo schermo
Ora creiamo la nostra prima schermata e chiamiamola welcomeScreen.js all'interno della cartella preAuthScreens .
preAuthScreens > welcomeScreen.js
Ecco il contenuto del nostro file 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
Ecco cosa abbiamo fatto nel blocco di codice sopra:
Innanzitutto, abbiamo importato le cose di cui abbiamo bisogno dalla libreria React Native, ovvero View
, Text
, Button
, TextInput
. Successivamente, abbiamo creato il nostro componente funzionale WelcomeScreen
.
Noterai che abbiamo importato lo StyleSheet
da React Native e l'abbiamo usato per definire gli stili per la nostra intestazione e anche per il nostro <TextInput />
.
Infine, esportiamo il componente WelcomeScreen
in fondo al codice.
Ora che abbiamo finito con questo, facciamo in modo che questo componente funzioni come previsto usando l'hook useState
per memorizzare i valori degli input e aggiornare i loro stati ogni volta che si verifica un cambiamento nei campi di input. Porteremo anche import l'hook useCallback
da React poiché ne avremo bisogno in seguito per mantenere una funzione.
Innanzitutto, mentre siamo ancora nel componente WelcomeScreen
, dobbiamo importare useState
e useCallback
da React.
import React, { useState, useCallback } from 'react';
Ora all'interno del componente funzionale WelcomeScreen
, creiamo rispettivamente i due stati per l'e-mail e la password:
... const WelcomeScreen = () => { const [email, setEmail] = useState('') const [password, setPassword] = useState('') return ( ... ) } ...
Successivamente, dobbiamo modificare i nostri campi <TextInput />
in modo che ottengano il loro valore dai rispettivi stati e aggiornino il loro stato quando il valore dell'input viene aggiornato:
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> ) } ...
Nel codice sopra, ecco cosa abbiamo fatto:
- Abbiamo fatto in modo che il
value
di ciascuno degli input di testo indichi i rispettivi stati. - Abbiamo aggiunto il gestore
onChangeText
ai nostri input di testo. Questo si attiva ogni volta che un nuovo valore viene inserito o eliminato dai campi di input. - Abbiamo chiamato la nostra funzione
onInputChange
che accetta due argomenti:- Il
value
corrente è fornito dal gestoreonChangeText
. - Il setter dello stato che deve essere aggiornato (per il primo campo di input passiamo
setEmail
e il secondosetPassword
. - Infine, scriviamo la nostra funzione
onInputChange
e la nostra funzione fa solo una cosa: aggiorna i rispettivi stati con il nuovo valore.
- Il
La prossima cosa su cui dobbiamo lavorare è la funzione onUserAuthentication()
con la quale viene chiamata ogni volta che si fa clic sul pulsante per l'invio del modulo.
Idealmente, l'utente deve aver già creato un account e l'accesso comporterà una logica di back-end di qualche tipo per verificare che l'utente esista e quindi assegnare un token all'utente. Nel nostro caso, poiché non stiamo utilizzando alcun back-end, creeremo un oggetto contenente i dettagli di accesso utente corretti, quindi autenticheremo un utente solo quando i valori che immettono corrispondono ai nostri valori fissi dall'oggetto di accesso dell'e- email
e della password
che faremo creare.
Ecco il codice di cui abbiamo bisogno per farlo:
... 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 ( ... ) } ...
Una delle prime cose che noterai nel codice sopra è che abbiamo definito un correctAuthenticationDetails
(che è un oggetto che contiene i dettagli di accesso corretti che ci aspettiamo che un utente fornisca) al di fuori del componente funzionale WelcomeScreen()
.
Successivamente, abbiamo scritto il contenuto della funzione onUserAuthentication()
e utilizzato un'istruzione condizionale per verificare se l'e- email
o la password
conservate nei rispettivi stati non corrispondono a quella che abbiamo fornito nel nostro oggetto.
Se vuoi vedere cosa abbiamo fatto finora, importa il componente WelcomeScreen nel tuo App.js in questo modo:
Apri il file App.js e inserisci questo sostituisci l'intero codice con questo:
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> ); }
Osservando attentamente il codice sopra, vedrai che quello che abbiamo fatto è stato importare il componente WelcomeScreen e quindi usarlo nella funzione App()
.
Ecco come appare il risultato del nostro WelcomeScreen
:
Ora che abbiamo finito di creare il componente WelcomeScreen , andiamo avanti e iniziamo a lavorare con l'API Context per la gestione del nostro stato globale.
Perché l'API di contesto?
Utilizzando Context API, non è necessario installare alcuna libreria aggiuntiva in ReactJS, è meno stressante da configurare ed è uno dei modi più popolari per gestire lo stato globale in ReactJS. Per la gestione dello stato leggero, è una buona scelta.
Creare il nostro contesto
Se ricordi, abbiamo creato una cartella di contesto in precedenza e creato una sottocartella al suo interno chiamata authContext .
Ora andiamo al file AuthContext.js nella cartella authContext e creiamo il nostro contesto:
contesto > authContext > AuthContext.js
import React, { createContext } from 'react'; const AuthContext = createContext(); export default AuthContext;
L' AuthContext
che abbiamo appena creato contiene il valore dello stato di loading
e i valori dello stato userToken
. Attualmente, nel createContext
che abbiamo dichiarato nel blocco di codice sopra, non abbiamo inizializzato alcun valore predefinito qui, quindi il nostro contesto è attualmente undefined
. Un valore di esempio del contesto di autenticazione potrebbe essere {loading: false, userToken: 'abcd}
Il file AuthState.js contiene la nostra logica dell'API Context e i relativi valori di stato. Le funzioni scritte qui possono essere chiamate da qualsiasi punto della nostra app e quando aggiornano i valori nello stato, viene aggiornato anche a livello globale.
Per prima cosa, portiamo tutte le importazioni di cui avremo bisogno in questo file:
contesto > AuthContext > AuthState.js
import React, { useState } from 'react'; import AuthContext from './AuthContext'; import AsyncStorage from '@react-native-community/async-storage';
Abbiamo importato l' useState()
da ReactJS per mantenere i nostri stati, abbiamo importato il file AuthContext che abbiamo creato sopra perché è qui che viene inizializzato il nostro contesto vuoto per l'autenticazione e dovremo usarlo come vedrai più avanti mentre procediamo , infine importiamo il pacchetto AsyncStorage
(simile a localStorage per il web).
AsyncStorage
è un'API React Native che consente di mantenere i dati offline sul dispositivo in un'applicazione 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;
Nel blocco di codice sopra, ecco cosa abbiamo fatto:
Abbiamo dichiarato due stati per
userToken
eisLoading
. Lo statouserToken
verrà utilizzato per archiviare il token salvato inAsyncStorage
, mentre lo statoisLoading
verrà utilizzato per tenere traccia dello stato di caricamento (inizialmente è impostato sutrue
). Scopriremo di più sull'uso di questi due stati mentre procediamo.Successivamente, abbiamo scritto la nostra funzione
onAuthentication()
. Questa funzione è una funzioneasync
che viene chiamata quando si fa clic sul pulsante di accesso dal filewelcomeScreen.jsx
. Questa funzione verrà chiamata solo se l'e-mail e la password fornite dall'utente corrispondono all'oggetto dei dettagli utente corretto che abbiamo fornito. Di solito ciò che accade durante l'autenticazione è che un token viene generato per l'utente dopo che l'utente è stato autenticato sul backend utilizzando un pacchetto come JWT e questo token viene inviato al frontend. Dal momento che non entreremo in tutto questo per questo tutorial, abbiamo creato un token statico e lo abbiamo mantenuto in una variabile chiamataUSER_TOKEN
.Successivamente, utilizziamo la parola chiave
await
per impostare il nostro token utente su AsyncStorage con il nomeuser-token
. L'istruzioneconsole.warn()
viene utilizzata solo per verificare che tutto sia andato per il verso giusto, puoi toglierla quando vuoi.Infine, passiamo la nostra funzione
onAuthenticated
come valore all'interno del nostro<AuthContext.Provider>
in modo da poter accedere e chiamare la funzione da qualsiasi punto della nostra app.
schermate > preAuth > welcomeScreen.js
Innanzitutto, importa useContext
da ReactJS e importa AuthContext
dal file AuthContext.js
.
import React, { useState, useContext } from 'react'; import AuthContext from '../../../context/authContext/AuthContext' ...
Ora, all'interno del componente funzionale welcomeScreen()
, utilizziamo il contesto che abbiamo creato:
... 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 ( ... ) } ...
Nel blocco di codice sopra, abbiamo destrutturato la funzione onAuthentication
dal nostro AuthContext
e poi l'abbiamo chiamata all'interno della nostra funzione onUserAuthentication()
e rimosso l'istruzione console.log console.log()
che era lì prima d'ora.
In questo momento, questo genererà un errore perché non abbiamo ancora accesso a AuthContext
. Per utilizzare AuthContext
ovunque nell'applicazione, è necessario eseguire il wrapping del file di primo livello nella nostra app con AuthState
(nel nostro caso, è il file App.js ).
Vai al file App.js e sostituisci il codice lì con questo:
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> ); }
Siamo arrivati così lontano e abbiamo finito con questa sezione. Prima di passare alla sezione successiva in cui impostiamo il nostro percorso, creiamo una nuova schermata. La schermata che stiamo per creare sarà il file HomeScreen.js che dovrebbe apparire solo dopo l'avvenuta autenticazione.
Vai a: schermate > postAuth .
Crea un nuovo file chiamato HomeScreen.js . Ecco il codice per il file HomeScreen.js :
schermate > 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
Per ora, il pulsante di disconnessione ha un'istruzione fittizia console.log()
. Successivamente, creeremo la funzionalità di logout e la passeremo allo schermo dal nostro contesto.
Allestimento dei nostri percorsi
Dobbiamo creare tre (3) file all'interno della nostra cartella di navigazione:
- postAuthNavigator.js ,
- preAuthNavigator.js ,
- AppNavigator.js .
Dopo aver creato questi tre file, vai al file preAuthNaviagtor.js che hai appena creato e scrivi questo:
navigazione > 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;
Nel file sopra, ecco cosa abbiamo fatto:
- Abbiamo importato
createStackNavigator
da@react-navigation/stack
che stiamo usando per la nostra navigazione nello stack. IlcreateStackNavigator
Fornisce un modo per la tua app di passare da una schermata all'altra in cui ogni nuova schermata è posizionata in cima a una pila. Per impostazione predefinita, il navigatore dello stack è configurato per avere il familiare look & feel di iOS e Android: le nuove schermate scorrono da destra su iOS, sfumano dal basso su Android. Clicca qui se vuoi saperne di più sullo stack navigator in React Native. - Abbiamo destrutturato
Navigator
eScreen
dacreateStackNavigator()
. - Nella nostra dichiarazione di reso, abbiamo creato la nostra navigazione con
<Navigator/>
e creato il nostro schermo con<Screen/>
. questo significa che se avessimo più schermate a cui è possibile accedere prima dell'autenticazione, avremo più<Screen/>
qui che le rappresentano. - Infine, esportiamo il nostro componente
PreAuthNavigator
.
Facciamo una cosa simile per il file postAuthNavigator.js
.
navigazione > 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;
Come vediamo nel codice sopra, l'unica differenza tra preAuthNavigator.js e postAuthNavigator.js è lo schermo che viene renderizzato. Mentre il primo prende la schermata di benvenuto, il postAuthNavigator.js WelcomeScreen
la HomeScreen
.
Per creare il nostro AppNavigator.js dobbiamo creare alcune cose.
Poiché AppNavigator.js è il punto in cui cambieremo e verificheremo quale percorso sarà disponibile per l'accesso da parte dell'utente, abbiamo bisogno di diverse schermate in atto affinché funzioni correttamente, descriviamo prima le cose che dobbiamo creare:
- TransitionScreen.js
Mentre l'app decide quale navigazione montare, vogliamo che venga visualizzata una schermata di transizione. In genere, la schermata di transizione sarà uno spinner di caricamento o qualsiasi altra animazione personalizzata scelta per l'app, ma nel nostro caso utilizzeremo un<Text/>
di base per visualizzareloading…
. -
checkAuthenticationStatus()
Questa funzione è ciò che chiameremo per controllare lo stato di autenticazione che determinerà quale stack di navigazione verrà montato. Creeremo questa funzione nel nostro contesto e la useremo in Appnavigator.js .
Ora andiamo avanti e creiamo il nostro file TransitionScreen.js .
schermate > TransitionScreen.js
import React from 'react'; import { Text, View } from 'react-native'; const TransitionScreen = () => { return ( <View> <Text>Loading...</Text> </View> ) } export default TransitionScreen
La nostra schermata di transizione è solo una semplice schermata che mostra il caricamento del testo. Vedremo dove usarlo mentre procediamo in questo articolo.
Quindi, andiamo al nostro AuthState.js e scriviamo il nostro checkAuthenticationStatus()
:
contesto > 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;
Nel blocco di codice sopra, abbiamo scritto la funzione checkAuthenticationStatus()
. Nella nostra funzione, ecco cosa stiamo facendo:
- Abbiamo usato la parola chiave
await
per ottenere il nostro token daAsyncStorage
. ConAsyncStorage
, se non viene fornito alcun token, restituiscenull
. Anche il nostro statouserToken
iniziale è impostato sunull
. - Usiamo
setUserToken
per impostare il nostro valore restituito daAsyncStorage
come nuovouserToken
. Se il valore restituito ènull
, significa che il nostrouserToken
rimanenull
. - Dopo il blocco
try{}…catch(){}
, impostiamoisLoading
su false perché la funzione per verificare lo stato di autenticazione è completa. Avremo bisogno del valore diisLoading
per sapere se dobbiamo ancora visualizzare ilTransitionScreen
o meno. Vale la pena considerare di impostare un errore se si verifica un errore durante il recupero del token in modo da poter mostrare all'utente un pulsante "Riprova" o "Riprova" quando si verifica l'errore. - Ogni volta che
AuthState
montato, vogliamo controllare lo stato di autenticazione, quindi utilizziamo l'useEffect()
ReactJS per farlo. Chiamiamo la nostra funzionecheckAuthenticationStatus()
all'internouseEffect()
e impostiamo il valore diisLoading
sufalse
una volta terminato. - Infine, aggiungiamo i nostri stati ai nostri valori
<AuthContext.Provider/>
in modo da potervi accedere da qualsiasi punto della nostra app coperta dall'API Context.
Ora che abbiamo la nostra funzione, è ora di tornare al nostro AppNavigator.js e scrivere il codice per montare un particolare navigatore di stack in base allo stato di autenticazione:
navigazione > AppNavigator.js
Innanzitutto, importeremo tutto ciò di cui abbiamo bisogno per il nostro 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";
Ora che abbiamo tutte le nostre importazioni, creiamo la funzione AppNavigator()
.
... const AppNavigator = () => { } export default AppNavigator
Successivamente, andremo ora a scrivere il contenuto della nostra funzione 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
Nel blocco di codice sopra, ecco uno schema di ciò che abbiamo fatto:
- Abbiamo creato un navigatore dello stack e da esso destrutturato il
Navigator
e loScreen
. - Abbiamo importato
userToken
eisLoading
dal nostroAuthContext
- Quando
AuthState
montato,checkAuthenticationStatus()
viene chiamatouseEffecct
lì. Usiamo l'istruzioneif
per verificare seisLoading
istrue
, se ètrue
lo schermo che restituiamo è il nostro<TransitionScreen />
che abbiamo creato in precedenza perché la funzionecheckAuthenticationStatus()
non è ancora completa. - Una volta che il nostro
checkAuthenticationStatus()
è completo,isLoading
è impostato sufalse
e restituiamo i nostri componenti di navigazione principali. - Il
NavigationContainer
è stato importato da@react-navigation/native
. Viene utilizzato solo una volta nel navigatore principale di primo livello. Si noti che non lo stiamo usando in preAuthNavigator.js o postAuthNavigator.js. - Nel nostro
AppNavigator()
, creiamo ancora uno stack navigator. SeuserToken
ottenuto dalla nostra Context API ènull
, montiamoPreAuthNavigator
, se il suo valore è qualcos'altro (il che significa cheAsyncStorage.getItem()
incheckAuthenticationStatus()
restituito un valore effettivo), quindi montiamoPostAuthNavigator
. Il nostro rendering condizionale viene eseguito utilizzando l'operatore ternario.
Ora abbiamo impostato il nostro AppNavigator.js . Successivamente, dobbiamo passare il nostro AppNavigator
nel nostro file App.js.
Passiamo il nostro AppNavigator
nel file App.js :
App.js
... import AppNavigator from './views/navigation/AppNavigator'; ... return ( <AuthState> <AppNavigator /> </AuthState> );
Vediamo ora come appare la nostra app in questo momento:
Ecco cosa succede quando fornisci una credenziale errata durante il tentativo di accesso:
Aggiunta della funzionalità di disconnessione
A questo punto, il nostro processo di autenticazione e selezione del percorso è completo. L'unica cosa rimasta per la nostra app è aggiungere la funzionalità di logout.
Il pulsante di disconnessione si trova nel file HomeScreen.js . Abbiamo passato una funzione onLogout()
all'attributo onPress
del pulsante. Per ora, abbiamo una semplice istruzione console.log()
nella nostra funzione, ma tra poco questo cambierà.
Ora andiamo al nostro AuthState.js e scriviamo la funzione per il logout. Questa funzione cancella semplicemente AsyncStorage
in cui è salvato il token utente.
contesto > authContext > AuthState.js
... const AuthState = (props) => { ... const userSignout = async() => { await AsyncStorage.removeItem('user-token'); setUserToken(null); } return ( ... ) } export default AuthState;
userSignout()
è una funzione asincrona che rimuove il user-token
dal nostro AsyncStorage
.
Ora dobbiamo chiamare la funzione userSignout()
nel nostro HomeScreen.js ogni volta che si fa clic sul pulsante di logout.
Andiamo al nostro HomeScreen.js e usiamo ther userSignout()
dal nostro AuthContext
.
schermate > 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> ) } ...
Nel blocco di codice sopra abbiamo importato l'hook useContext
da ReactJS, quindi abbiamo importato il nostro AuthContext. Successivamente, abbiamo destrutturato la funzione userSignout
dal nostro AuthContext
e questa funzione userSignout()
viene chiamata nella nostra funzione onLogout()
.
Ora, ogni volta che si fa clic sul pulsante di disconnessione, il token utente nel nostro AsyncStorage
viene cancellato.
Ecco! il nostro intero processo è finito.
Ecco cosa succede quando premi il pulsante Indietro dopo aver effettuato l'accesso:
Ecco cosa succede quando premi il pulsante Indietro dopo esserti disconnesso:
Ecco alcuni comportamenti diversi che notiamo quando utilizziamo questo modello nel nostro cambio di stack di navigazione:
- Noterai che non c'era nessun punto in cui dovessimo usare
navigation.navigate()
onavigation.push()
per passare a un'altra rotta dopo il login. Una volta che il nostro stato è stato aggiornato con il token utente, lo stack di navigazione visualizzato viene modificato automaticamente. - Premendo il pulsante Indietro sul dispositivo dopo che l'accesso è riuscito non è possibile tornare alla pagina di accesso, ma si chiude completamente l'app. Questo comportamento è importante perché non si desidera che l'utente possa tornare alla pagina di accesso a meno che non si disconnette dall'app. La stessa cosa vale per il logout: una volta che l'utente si è disconnesso, non può utilizzare il pulsante Indietro per tornare alla schermata
HomeScreen
, ma invece l'app si chiude.
Conclusione
In molte App, l'autenticazione è una delle parti più importanti perché conferma che la persona che tenta di accedere ai contenuti protetti ha il diritto di accedere alle informazioni. Imparare a farlo nel modo giusto è un passo importante nella creazione di un'applicazione fantastica, intuitiva e facile da usare/navigare.
Basandosi su questo codice, ecco alcune cose che potresti considerare di aggiungere:
- Convalida del modulo per la convalida dei campi di input. Dai un'occhiata alla convalida del modulo React Native con Formik e Yup.
- Autenticazione Firebase per l'integrazione dell'autenticazione con Gmail, Github, Facebook, Twitter o la tua interfaccia personalizzata. Dai un'occhiata a React Native Firebase.
- Concetti di codice per i progettisti: autenticazione e autorizzazione.
Ecco anche alcune risorse importanti che ho trovato che ti illumineranno di più sull'autenticazione, la sicurezza e su come farlo correttamente:
Risorse
- React Native: Spiegazione del flusso di autenticazione utente
- 10 Migliori pratiche di sicurezza di reazione
- Metodi di autenticazione che possono prevenire la prossima violazione
- Visualizza qui una build/anteprima dal vivo della nostra applicazione;
- Visualizza il progetto su GitHub.