Gestion du montage et du démontage des itinéraires de navigation dans React Native
Publié: 2022-03-10Dans cet article, nous allons parcourir le montage et le démontage des itinéraires de navigation dans React Native. Un comportement attendu de votre application est qu'une fois la condition d'authentification remplie, un nouvel ensemble d'itinéraires de navigation est disponible uniquement pour les utilisateurs connectés, tandis que les autres écrans qui étaient affichés avant la suppression de l'authentification et ne peuvent pas être retournés à moins que le l'utilisateur se déconnecte de l'application.
Pour la sécurité de votre application, les itinéraires protégés vous permettent de n'afficher certaines informations/contenus de votre application qu'à des utilisateurs spécifiques, tout en limitant l'accès aux personnes non autorisées.
Nous travaillerons avec Expo pour ce projet car cela nous aidera à nous concentrer sur le problème en cours au lieu de nous soucier de beaucoup de configurations. Les mêmes étapes exactes dans cet article pourraient être suivies pour une application React Native nue.
Vous devez vous familiariser avec JavaScript et React Native pour suivre ce didacticiel. Voici quelques éléments importants que vous devriez déjà connaître :
- Composants personnalisés dans React Native (comment créer des composants, recevoir, transmettre et utiliser des accessoires dans un composant). Lire la suite.
- Réagissez la navigation. Lire la suite.
- Navigateur de pile dans React Native. Lire la suite.
- Connaissance de base des composants React Native Core (
<View/>
,<Text/>
, etc.). Lire la suite. - Réagissez Native
AsyncStorage
. Lire la suite. - API de contexte. Lire la suite.
Configuration du projet et authentification de base
Si vous débutez avec expo et que vous ne savez pas comment installer expo, consultez la documentation officielle. Une fois l'installation terminée, lancez-vous pour initialiser un nouveau projet React Native avec expo depuis notre invite de commande :
expo init navigation-project
Il vous sera présenté quelques options pour choisir comment vous voulez que la configuration de base soit :
Dans notre cas, sélectionnons la première option pour configurer notre projet en tant que document vierge. Maintenant, attendez que l'installation des dépendances JavaScript soit terminée.
Une fois notre application configurée, nous pouvons changer notre répertoire en notre nouveau répertoire de projet et l'ouvrir dans votre éditeur de code préféré. Nous devons installer la bibliothèque que nous utiliserons pour AsyncStorage
et nos bibliothèques de navigation. Dans votre répertoire de dossiers dans votre terminal, collez la commande ci-dessus et choisissez un modèle (le blank
fonctionnerait) pour installer nos dépendances de projet.
Regardons à quoi sert chacune de ces dépendances :
- @react-native-community/async-stockage
Comme localStorage sur le Web, il s'agit d'une API React Native pour la persistance des données sur un appareil dans des paires clé-valeur. - @react-native-community/masked-view, react-native-screens, react-native-gesture-handle
Ces dépendances sont des utilitaires de base utilisés par la plupart des navigateurs pour créer la structure de navigation dans l'application. (En savoir plus dans Premiers pas avec la navigation React Native.) - @react-navigation/native
C'est la dépendance pour la navigation React Native. - @react-navigation/pile
Il s'agit de la dépendance pour la navigation dans la pile dans 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
Pour démarrer l'application, utilisez expo start
à partir du répertoire de l'application dans votre terminal. Une fois l'application démarrée, vous pouvez utiliser l'application expo depuis votre téléphone portable pour scanner le code-barres et afficher l'application, ou si vous avez un émulateur Android/simulateur IOS, vous pouvez ouvrir l'application via eux à partir de l'outil de développement expo qui s'ouvre dans votre navigateur lorsque vous démarrez une application expo. Pour les exemples d'images de cet article, nous utiliserons Genymotions pour voir notre résultat. Voici à quoi ressemblera notre résultat final dans Genymotions :
Structures de dossiers
Créons notre structure de dossiers dès le début afin qu'il nous soit plus facile de travailler avec elle au fur et à mesure que nous procédons :
Nous avons d'abord besoin de deux dossiers :
- le contexte
Ce dossier contiendra le contexte de l'ensemble de notre application car nous travaillerons avec l'API de contexte pour la gestion globale de l'état. - vues
Ce dossier contiendra à la fois le dossier de navigation et les vues des différents écrans.
Allez-y et créez les deux dossiers dans votre répertoire de projet.
Dans le dossier de contexte, créez un dossier appelé authContext et créez deux fichiers à l'intérieur du dossier authContext :
- AuthContext.js ,
- AuthState.js .
Nous aurons besoin de ces fichiers lorsque nous commencerons à travailler avec Context API.
Allez maintenant dans le dossier des vues que nous avons créé et créez deux autres dossiers à l'intérieur, à savoir :
- naviguer ,
- écrans .
Maintenant, nous n'avons pas encore fini, dans le dossier screens , créez ces deux autres dossiers :
- postAuthScreens ,
- preAuthScreens .
Si vous avez correctement suivi la configuration du dossier, voici à quoi devrait ressembler la structure de votre dossier pour le moment :
Création de notre premier écran
Créons maintenant notre premier écran et appelons-le welcomeScreen.js dans le dossier preAuthScreens .
preAuthScreens > welcomeScreen.js
Voici le contenu de notre fichier 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
Voici ce que nous avons fait dans le bloc de code ci-dessus :
Tout d'abord, nous avons importé les éléments dont nous avons besoin de la bibliothèque React Native, à savoir View
, Text
, Button
, TextInput
. Ensuite, nous avons créé notre composant fonctionnel WelcomeScreen
.
Vous remarquerez que nous avons importé le StyleSheet
de React Native et que nous l'avons utilisé pour définir des styles pour notre en-tête ainsi que pour notre <TextInput />
.
Enfin, nous exportons le composant WelcomeScreen
en bas du code.
Maintenant que nous en avons terminé, faisons en sorte que ce composant fonctionne comme prévu en utilisant le crochet useState
pour stocker les valeurs des entrées et mettre à jour leurs états chaque fois qu'un changement se produit dans les champs d'entrée. Nous allons également importer le crochet useCallback
de React car nous en aurons besoin plus tard pour tenir une fonction.
Tout d'abord, alors que nous sommes toujours dans le composant WelcomeScreen
, nous devons importer les useState
et useCallback
de React.
import React, { useState, useCallback } from 'react';
Maintenant, dans le composant fonctionnel WelcomeScreen
, créons respectivement les deux états pour l'e-mail et le mot de passe :
... const WelcomeScreen = () => { const [email, setEmail] = useState('') const [password, setPassword] = useState('') return ( ... ) } ...
Ensuite, nous devons modifier nos champs <TextInput />
afin qu'ils obtiennent leur valeur à partir de leurs états respectifs et mettent à jour leur état lorsque la valeur de l'entrée est mise à jour :
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> ) } ...
Dans le code ci-dessus, voici ce que nous avons fait :
- Nous avons fait en sorte que la
value
de chacune des entrées de texte pointe vers leurs états respectifs. - Nous avons ajouté le gestionnaire
onChangeText
à nos entrées de texte. Cela se déclenche à chaque fois qu'une nouvelle valeur est saisie ou supprimée des champs de saisie. - Nous avons appelé notre fonction
onInputChange
qui accepte deux arguments :- La
value
actuelle est fournie par le gestionnaireonChangeText
. - Le setter de l'état qui doit être mis à jour (pour le premier champ de saisie nous passons
setEmail
et le second nous passonssetPassword
. - Enfin, nous écrivons notre fonction
onInputChange
, et notre fonction ne fait qu'une chose : elle met à jour les états respectifs avec la nouvelle valeur.
- La
La prochaine chose sur laquelle nous devons travailler est la fonction onUserAuthentication()
qui est appelée chaque fois que le bouton de soumission du formulaire est cliqué.
Idéalement, l'utilisateur doit déjà avoir créé un compte et la connexion impliquera une sorte de logique backend pour vérifier que l'utilisateur existe, puis attribuer un jeton à l'utilisateur. Dans notre cas, puisque nous n'utilisons aucun backend, nous allons créer un objet contenant les informations de connexion correctes de l'utilisateur, puis authentifier un utilisateur uniquement lorsque les valeurs qu'il entre correspondent à nos valeurs fixes à partir de l'objet de connexion de l'e- email
et du mot de password
que nous allons créer.
Voici le code dont nous avons besoin pour le faire :
... 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 ( ... ) } ...
L'une des premières choses que vous remarquerez dans le code ci-dessus est que nous avons défini un correctAuthenticationDetails
(qui est un objet qui contient les informations de connexion correctes que nous attendons d'un utilisateur) en dehors du composant fonctionnel WelcomeScreen()
.
Ensuite, nous avons écrit le contenu de la fonction onUserAuthentication()
et utilisé une instruction conditionnelle pour vérifier si l'e- email
ou le mot de password
conservé dans les états respectifs ne correspond pas à celui que nous avons fourni dans notre objet.
Si vous souhaitez voir ce que nous avons fait jusqu'à présent, importez le composant WelcomeScreen dans votre App.js comme ceci :
Ouvrez le fichier App.js et mettez ceci remplacez tout le code par ceci :
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> ); }
En regardant attentivement le code ci-dessus, vous verrez que nous avons importé le composant WelcomeScreen , puis l'avons utilisé dans la fonction App()
.
Voici à quoi ressemble le résultat de notre WelcomeScreen
:
Maintenant que nous avons fini de créer le composant WelcomeScreen , allons de l'avant et commençons à travailler avec l'API Context pour gérer notre état global.
Pourquoi l'API contextuelle ?
En utilisant Context API, nous n'avons pas besoin d'installer de bibliothèque supplémentaire dans ReactJS, c'est moins stressant à configurer et c'est l'un des moyens les plus populaires de gérer l'état global dans ReactJS. Pour une gestion d'état légère, c'est un bon choix.
Créer notre contexte
Si vous vous souvenez, nous avons créé un dossier de contexte plus tôt et créé un sous-dossier à l'intérieur de celui-ci appelé authContext .
Naviguons maintenant vers le fichier AuthContext.js dans le dossier authContext et créons notre contexte :
contexte > authContext > AuthContext.js
import React, { createContext } from 'react'; const AuthContext = createContext(); export default AuthContext;
Le AuthContext
que nous venons de créer contient la valeur d'état loading
et les valeurs d'état userToken
. Actuellement, dans le createContext
que nous avons déclaré dans le bloc de code ci-dessus, nous n'avons initialisé aucune valeur par défaut ici, donc notre contexte est actuellement undefined
. Un exemple de valeur du contexte d'authentification pourrait être {loading: false, userToken: 'abcd}
Le fichier AuthState.js contient notre logique d'API de contexte et leurs valeurs d'état. Les fonctions écrites ici peuvent être appelées de n'importe où dans notre application et lorsqu'elles mettent à jour les valeurs dans l'état, elles sont également mises à jour globalement.
Tout d'abord, apportons toutes les importations dont nous aurons besoin dans ce fichier :
contexte > AuthContext > AuthState.js
import React, { useState } from 'react'; import AuthContext from './AuthContext'; import AsyncStorage from '@react-native-community/async-storage';
Nous avons importé le crochet useState()
de ReactJS pour contenir nos états, nous avons importé le fichier AuthContext que nous avons créé ci-dessus car c'est là que notre contexte vide pour l'authentification est initialisé et nous devrons l'utiliser comme vous le verrez plus tard pendant que nous progressons , enfin nous importons le package AsyncStorage
(similaire à localStorage pour le web).
AsyncStorage
est une API React Native qui vous permet de conserver des données hors ligne sur l'appareil dans une application 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;
Dans le bloc de code ci-dessus, voici ce que nous avons fait :
Nous avons déclaré deux états pour
userToken
etisLoading
. L'étatuserToken
sera utilisé pour stocker le jeton enregistré dansAsyncStorage
, tandis que l'étatisLoading
sera utilisé pour suivre l'état de chargement (initialement, il est défini surtrue
). Nous en apprendrons davantage sur l'utilisation de ces deux états au fur et à mesure.Ensuite, nous avons écrit notre fonction
onAuthentication()
. Cette fonction est une fonctionasync
qui est appelée lorsque le bouton de connexion est cliqué à partir du fichierwelcomeScreen.jsx
. Cette fonction ne sera appelée que si l'e-mail et le mot de passe fournis par l'utilisateur correspondent à l'objet de détails utilisateur correct que nous avons fourni. Habituellement, ce qui se passe lors de l'authentification, c'est qu'un jeton est généré pour l'utilisateur après que l'utilisateur est authentifié sur le backend à l'aide d'un package comme JWT, et ce jeton est envoyé au frontend. Comme nous n'aborderons pas tout cela pour ce didacticiel, nous avons créé un jeton statique et l'avons conservé dans une variable appeléeUSER_TOKEN
.Ensuite, nous utilisons le mot clé
await
pour définir notre jeton utilisateur sur AsyncStorage avec le nomuser-token
. L'console.warn()
est juste utilisée pour vérifier que tout s'est bien passé, vous pouvez l'enlever quand vous le souhaitez.Enfin, nous transmettons notre fonction
onAuthenticated
en tant que valeur dans notre<AuthContext.Provider>
afin que nous puissions accéder et appeler la fonction depuis n'importe où dans notre application.
screens > preAuth > welcomeScreen.js
Tout d'abord, importez useContext
depuis ReactJS et importez AuthContext
depuis le fichier AuthContext.js
.
import React, { useState, useContext } from 'react'; import AuthContext from '../../../context/authContext/AuthContext' ...
Maintenant, à l'intérieur du composant fonctionnel welcomeScreen()
, utilisons le contexte que nous avons créé :
... 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 ( ... ) } ...
Dans le bloc de code ci-dessus, nous avons déstructuré la fonction onAuthentication
de notre AuthContext
, puis nous l'avons appelée dans notre fonction onUserAuthentication()
et avons supprimé l' console.log()
qui s'y trouvait auparavant.
Pour le moment, cela générera une erreur car nous n'avons pas encore accès à AuthContext
. Pour utiliser AuthContext
n'importe où dans votre application, nous devons encapsuler le fichier de niveau supérieur dans notre application avec AuthState
(dans notre cas, il s'agit du fichier App.js ).
Accédez au fichier App.js et remplacez le code par ceci :
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> ); }
Nous sommes arrivés si loin et nous en avons fini avec cette section. Avant de passer à la section suivante où nous configurons notre routage, créons un nouvel écran. L'écran que nous sommes sur le point de créer sera le fichier HomeScreen.js qui est censé n'apparaître qu'après une authentification réussie.
Accédez à : screens > postAuth .
Créez un nouveau fichier appelé HomeScreen.js . Voici le code du fichier HomeScreen.js :
screens > 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
Pour l'instant, le bouton de déconnexion a une instruction factice console.log()
. Plus tard, nous créerons la fonctionnalité de déconnexion et la passerons à l'écran à partir de notre contexte.
Configuration de nos itinéraires
Nous devons créer trois (3) fichiers dans notre dossier de navigation :
- postAuthNavigator.js ,
- preAuthNavigator.js ,
- AppNavigator.js .
Une fois que vous avez créé ces trois fichiers, accédez au fichier preAuthNaviagtor.js que vous venez de créer et écrivez ceci :
navigation > 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;
Dans le fichier ci-dessus, voici ce que nous avons fait :
- Nous avons importé le
createStackNavigator
du@react-navigation/stack
que nous utilisons pour notre navigation dans la pile. LecreateStackNavigator
Fournit à votre application un moyen de passer d'un écran à l'autre où chaque nouvel écran est placé au-dessus d'une pile. Par défaut, le navigateur de pile est configuré pour avoir l'apparence familière d'iOS et d'Android : de nouveaux écrans apparaissent à partir de la droite sur iOS, apparaissent en fondu à partir du bas sur Android. Cliquez ici si vous souhaitez en savoir plus sur le navigateur de pile dans React Native. - Nous avons déstructuré
Navigator
etScreen
ducreateStackNavigator()
. - Dans notre déclaration de retour, nous avons créé notre navigation avec le
<Navigator/>
et créé notre écran avec le<Screen/>
. cela signifie que si nous avions plusieurs écrans accessibles avant l'authentification, nous aurons ici plusieurs balises<Screen/>
les représentant. - Enfin, nous exportons notre composant
PreAuthNavigator
.
Faisons la même chose pour le fichier postAuthNavigator.js
.
navigation > 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;
Comme nous le voyons dans le code ci-dessus, la seule différence entre le preAuthNavigator.js et le postAuthNavigator.js est l'écran rendu. Alors que le premier prend le WelcomeScreen
, le postAuthNavigator.js prend le HomeScreen
.
Pour créer notre AppNavigator.js, nous devons créer quelques éléments.
Étant donné que AppNavigator.js est l'endroit où nous allons changer et vérifier quel itinéraire sera disponible pour l'accès par l'utilisateur, nous avons besoin de plusieurs écrans en place pour que cela fonctionne correctement, décrivons les éléments que nous devons créer en premier :
- TransitionScreen.js
Pendant que l'application décide quelle navigation elle va monter, nous voulons qu'un écran de transition s'affiche. Généralement, l'écran de transition sera un spinner de chargement ou toute autre animation personnalisée choisie pour l'application, mais dans notre cas, nous utiliserons une<Text/>
de base pour afficher leloading…
. -
checkAuthenticationStatus()
Cette fonction est ce que nous appellerons pour vérifier le statut d'authentification qui déterminera quelle pile de navigation va être montée. Nous allons créer cette fonction dans notre contexte et l'utiliser dans le Appnavigator.js .
Maintenant, allons-y et créons notre fichier TransitionScreen.js .
écrans > TransitionScreen.js
import React from 'react'; import { Text, View } from 'react-native'; const TransitionScreen = () => { return ( <View> <Text>Loading...</Text> </View> ) } export default TransitionScreen
Notre écran de transition n'est qu'un simple écran qui affiche le chargement du texte. Nous verrons où l'utiliser au fur et à mesure de cet article.
Ensuite, allons dans notre AuthState.js et écrivons notre checkAuthenticationStatus()
:
contexte > 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;
Dans le bloc de code ci-dessus, nous avons écrit la fonction checkAuthenticationStatus()
. Dans notre fonction, voici ce que nous faisons :
- Nous avons utilisé le mot clé
await
pour obtenir notre jeton depuisAsyncStorage
. AvecAsyncStorage
, si aucun jeton n'est fourni, il renvoienull
. Notre étatuserToken
initial est également défini surnull
. - Nous utilisons le
setUserToken
pour définir notre valeur renvoyée parAsyncStorage
comme notre nouveauuserToken
. Si la valeur renvoyée estnull
, cela signifie que notreuserToken
restenull
. - Après le bloc
try{}…catch(){}
, nous définissonsisLoading
sur false car la fonction de vérification de l'état d'authentification est terminée. Nous aurons besoin de la valeur deisLoading
pour savoir si nous devons toujours afficher leTransitionScreen
ou non. Il vaut la peine d'envisager de définir une erreur s'il y a une erreur lors de la récupération du jeton afin que nous puissions montrer à l'utilisateur un bouton "Réessayer" ou "Réessayer" lorsque l'erreur se produit. - Chaque fois que
AuthState
monte, nous voulons vérifier l'état de l'authentification, nous utilisons donc leuseEffect()
ReactJS pour ce faire. Nous appelons notre fonctioncheckAuthenticationStatus()
à l'intérieur du crochetuseEffect()
et définissons la valeur deisLoading
surfalse
lorsque cela est fait. - Enfin, nous ajoutons nos états à nos
<AuthContext.Provider/>
afin de pouvoir y accéder depuis n'importe où dans notre application couverte par l'API Context.
Maintenant que nous avons notre fonction, il est temps de revenir à notre AppNavigator.js et d'écrire le code pour monter un navigateur de pile particulier en fonction du statut d'authentification :
navigation > AppNavigator.js
Tout d'abord, nous allons importer tout ce dont nous avons besoin pour notre 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";
Maintenant que nous avons toutes nos importations, créons la fonction AppNavigator()
.
... const AppNavigator = () => { } export default AppNavigator
Ensuite, nous allons maintenant écrire le contenu de notre fonction 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
Dans le bloc de code ci-dessus, voici un aperçu de ce que nous avons fait :
- Nous avons créé un navigateur de pile et déstructuré le
Navigator
et l'Screen
à partir de celui-ci. - Nous avons importé le
userToken
et leisLoading
de notreAuthContext
- Lorsque
AuthState
est monté, lecheckAuthenticationStatus()
est appelé dans le crochetuseEffecct
. Nous utilisons l'instructionif
pour vérifier siisLoading
esttrue
, si c'esttrue
, l'écran que nous renvoyons est notre<TransitionScreen />
que nous avons créé précédemment car la fonctioncheckAuthenticationStatus()
n'est pas encore terminée. - Une fois notre
checkAuthenticationStatus()
terminé,isLoading
est défini surfalse
et nous renvoyons nos principaux composants de navigation. - Le
NavigationContainer
a été importé depuis le@react-navigation/native
. Il n'est utilisé qu'une seule fois dans le navigateur principal de niveau supérieur. Notez que nous n'utilisons pas ceci dans preAuthNavigator.js ou postAuthNavigator.js. - Dans notre
AppNavigator()
, nous créons toujours un navigateur de pile. Si leuserToken
obtenu de notre API de contexte estnull
, nous montons lePreAuthNavigator
, si sa valeur est autre chose (ce qui signifie que leAsyncStorage.getItem()
dans lecheckAuthenticationStatus()
renvoyé une valeur réelle), alors nous montons lePostAuthNavigator
. Notre rendu conditionnel est fait en utilisant l'opérateur ternaire.
Nous avons maintenant configuré notre AppNavigator.js . Ensuite, nous devons passer notre AppNavigator
dans notre fichier App.js.
Passons notre AppNavigator
dans le fichier App.js :
App.js
... import AppNavigator from './views/navigation/AppNavigator'; ... return ( <AuthState> <AppNavigator /> </AuthState> );
Voyons maintenant à quoi ressemble notre application pour le moment :
Voici ce qui se passe lorsque vous fournissez des informations d'identification incorrectes lors de la tentative de connexion :
Ajout de la fonctionnalité de déconnexion
À ce stade, notre processus d'authentification et de sélection d'itinéraire est terminé. La seule chose qui reste à notre application est d'ajouter la fonctionnalité de déconnexion.
Le bouton de déconnexion se trouve dans le fichier HomeScreen.js . Nous avons passé une fonction onLogout()
à l'attribut onPress
du bouton. Pour l'instant, nous avons une simple console.log()
dans notre fonction, mais cela va changer dans peu de temps.
Maintenant, allons à notre AuthState.js et écrivons la fonction de déconnexion. Cette fonction efface simplement l' AsyncStorage
où le jeton utilisateur est enregistré.
contexte > authContext > AuthState.js
... const AuthState = (props) => { ... const userSignout = async() => { await AsyncStorage.removeItem('user-token'); setUserToken(null); } return ( ... ) } export default AuthState;
userSignout()
est une fonction asynchrone qui supprime le user-token
de notre AsyncStorage
.
Nous devons maintenant appeler la fonction userSignout()
dans notre HomeScreen.js chaque fois que le bouton de déconnexion est cliqué.
Allons à notre HomeScreen.js et utilisons userSignout()
de notre AuthContext
.
screens > 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> ) } ...
Dans le bloc de code ci-dessus, nous avons importé le crochet useContext
de ReactJS, puis nous avons importé notre AuthContext. Ensuite, nous avons déstructuré la fonction userSignout
de notre AuthContext
et cette fonction userSignout()
est appelée dans notre fonction onLogout()
.
Désormais, chaque fois que vous cliquez sur notre bouton de déconnexion, le jeton d'utilisateur dans notre AsyncStorage
est effacé.
Voila ! tout notre processus est terminé.
Voici ce qui se passe lorsque vous appuyez sur le bouton de retour après vous être connecté :
Voici ce qui se passe lorsque vous appuyez sur le bouton de retour après vous être déconnecté :
Voici quelques comportements différents que nous remarquons lors de l'utilisation de ce modèle dans notre changement de pile de navigation :
- Vous remarquerez qu'il n'y avait nulle part besoin d'utiliser
navigation.navigate()
ounavigation.push()
pour accéder à un autre itinéraire après la connexion. Une fois que notre état est mis à jour avec le jeton utilisateur, la pile de navigation rendue est automatiquement modifiée. - Si vous appuyez sur le bouton de retour de votre appareil une fois la connexion réussie, vous ne pourrez pas revenir à la page de connexion, mais cela fermera complètement l'application. Ce comportement est important car vous ne voulez pas que l'utilisateur puisse revenir à la page de connexion, sauf s'il se déconnecte de l'application. La même chose s'applique à la déconnexion - une fois que l'utilisateur se déconnecte, il ne peut pas utiliser le bouton de retour pour revenir à l'écran
HomeScreen
, mais à la place, l'application se ferme.
Conclusion
Dans de nombreuses applications, l'authentification est l'une des parties les plus importantes car elle confirme que la personne qui tente d'accéder au contenu protégé a le droit d'accéder aux informations. Apprendre à bien faire les choses est une étape importante dans la création d'une application géniale, intuitive et facile à utiliser/naviguer.
En partant de ce code, voici quelques éléments que vous pourriez envisager d'ajouter :
- Validation de formulaire pour valider les champs de saisie. Découvrez la validation de formulaire React Native avec Formik et Yup.
- Authentification Firebase pour intégrer l'authentification avec Gmail, Github, Facebook, Twitter ou votre interface personnalisée. Découvrez React Native Firebase.
- Concepts de code pour les concepteurs : authentification et autorisation.
Voici également quelques ressources importantes que j'ai trouvées qui vous éclaireront davantage sur l'authentification, la sécurité et la façon de bien faire les choses :
Ressources
- React Native : explication du flux d'authentification des utilisateurs
- 10 bonnes pratiques de sécurité React
- Méthodes d'authentification qui peuvent empêcher la prochaine violation
- Voir une version en direct/aperçu de notre application ici ;
- Voir le projet sur GitHub.