Gestione del montaggio e smontaggio di rotte di navigazione in React Native

Pubblicato: 2022-03-10
Riepilogo rapido ↬ Spesso sono necessari due diversi set di stack di navigazione per l'autenticazione prima e dopo l'autenticazione dell'utente. Di solito, per vedere più contenuti, devi essere autenticato in qualche modo. Diamo un'occhiata a come montare e smontare lo stack di navigazione in base a una condizione soddisfatta in React Native.

In 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:

Configurazione di base del progetto React Native
(Grande anteprima)

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:

risultato finale in Genymotions
(Grande anteprima)

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:

struttura delle cartelle
(Grande anteprima)
Altro dopo il salto! Continua a leggere sotto ↓

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 gestore onChangeText .
    • Il setter dello stato che deve essere aggiornato (per il primo campo di input passiamo setEmail e il secondo setPassword .
    • Infine, scriviamo la nostra funzione onInputChange e la nostra funzione fa solo una cosa: aggiorna i rispettivi stati con il nuovo valore.

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 :

il risultato di WelcomeScreen
(Grande anteprima)

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 e isLoading . Lo stato userToken verrà utilizzato per archiviare il token salvato in AsyncStorage , mentre lo stato isLoading verrà utilizzato per tenere traccia dello stato di caricamento (inizialmente è impostato su true ). Scopriremo di più sull'uso di questi due stati mentre procediamo.

  • Successivamente, abbiamo scritto la nostra funzione onAuthentication() . Questa funzione è una funzione async che viene chiamata quando si fa clic sul pulsante di accesso dal file welcomeScreen.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 chiamata USER_TOKEN .

  • Successivamente, utilizziamo la parola chiave await per impostare il nostro token utente su AsyncStorage con il nome user-token . L'istruzione console.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. Il createStackNavigator 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 e Screen da createStackNavigator() .
  • 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:

  1. 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 visualizzare loading… .
  2. 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 da AsyncStorage . Con AsyncStorage , se non viene fornito alcun token, restituisce null . Anche il nostro stato userToken iniziale è impostato su null .
  • Usiamo setUserToken per impostare il nostro valore restituito da AsyncStorage come nuovo userToken . Se il valore restituito è null , significa che il nostro userToken rimane null .
  • Dopo il blocco try{}…catch(){} , impostiamo isLoading su false perché la funzione per verificare lo stato di autenticazione è completa. Avremo bisogno del valore di isLoading per sapere se dobbiamo ancora visualizzare il TransitionScreen 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 funzione checkAuthenticationStatus() all'interno useEffect() e impostiamo il valore di isLoading su false 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 lo Screen .
  • Abbiamo importato userToken e isLoading dal nostro AuthContext
  • Quando AuthState montato, checkAuthenticationStatus() viene chiamato useEffecct lì. Usiamo l'istruzione if per verificare se isLoading is true , se è true lo schermo che restituiamo è il nostro <TransitionScreen /> che abbiamo creato in precedenza perché la funzione checkAuthenticationStatus() non è ancora completa.
  • Una volta che il nostro checkAuthenticationStatus() è completo, isLoading è impostato su false 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. Se userToken ottenuto dalla nostra Context API è null , montiamo PreAuthNavigator , se il suo valore è qualcos'altro (il che significa che AsyncStorage.getItem() in checkAuthenticationStatus() restituito un valore effettivo), quindi montiamo PostAuthNavigator . 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:

Premendo il pulsante Indietro dopo aver effettuato l'accesso all'app.

Ecco cosa succede quando premi il pulsante Indietro dopo esserti disconnesso:

Premendo il pulsante Indietro dopo aver effettuato il logout dall'app.

Ecco alcuni comportamenti diversi che notiamo quando utilizziamo questo modello nel nostro cambio di stack di navigazione:

  1. Noterai che non c'era nessun punto in cui dovessimo usare navigation.navigate() o navigation.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.
  2. 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.