Gestion du montage et du démontage des itinéraires de navigation dans React Native

Publié: 2022-03-10
Résumé rapide ↬ Vous avez souvent besoin de deux ensembles différents de piles de navigation pour l'authentification avant et après l'utilisateur. Habituellement, pour voir plus de contenu, vous devez être authentifié d'une manière ou d'une autre. Voyons comment monter et démonter la pile de navigation en fonction d'une condition remplie dans React Native.

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

Configuration de base du projet React Native
( Grand aperçu )

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 :

résultat final dans Genymotions
( Grand aperçu )

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 :

structure des dossiers
( Grand aperçu )
Plus après saut! Continuez à lire ci-dessous ↓

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 gestionnaire onChangeText .
    • Le setter de l'état qui doit être mis à jour (pour le premier champ de saisie nous passons setEmail et le second nous passons setPassword .
    • 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 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 :

le résultat de WelcomeScreen
( Grand aperçu )

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 et isLoading . L'état userToken sera utilisé pour stocker le jeton enregistré dans AsyncStorage , tandis que l'état isLoading sera utilisé pour suivre l'état de chargement (initialement, il est défini sur true ). 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 fonction async qui est appelée lorsque le bouton de connexion est cliqué à partir du fichier welcomeScreen.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ée USER_TOKEN .

  • Ensuite, nous utilisons le mot clé await pour définir notre jeton utilisateur sur AsyncStorage avec le nom user-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. Le createStackNavigator 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 et Screen du createStackNavigator() .
  • 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 :

  1. 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 le loading… .
  2. 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 depuis AsyncStorage . Avec AsyncStorage , si aucun jeton n'est fourni, il renvoie null . Notre état userToken initial est également défini sur null .
  • Nous utilisons le setUserToken pour définir notre valeur renvoyée par AsyncStorage comme notre nouveau userToken . Si la valeur renvoyée est null , cela signifie que notre userToken reste null .
  • Après le bloc try{}…catch(){} , nous définissons isLoading sur false car la fonction de vérification de l'état d'authentification est terminée. Nous aurons besoin de la valeur de isLoading pour savoir si nous devons toujours afficher le TransitionScreen 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 le useEffect() ReactJS pour ce faire. Nous appelons notre fonction checkAuthenticationStatus() à l'intérieur du crochet useEffect() et définissons la valeur de isLoading sur false 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 le isLoading de notre AuthContext
  • Lorsque AuthState est monté, le checkAuthenticationStatus() est appelé dans le crochet useEffecct . Nous utilisons l'instruction if pour vérifier si isLoading est true , si c'est true , l'écran que nous renvoyons est notre <TransitionScreen /> que nous avons créé précédemment car la fonction checkAuthenticationStatus() n'est pas encore terminée.
  • Une fois notre checkAuthenticationStatus() terminé, isLoading est défini sur false 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 le userToken obtenu de notre API de contexte est null , nous montons le PreAuthNavigator , si sa valeur est autre chose (ce qui signifie que le AsyncStorage.getItem() dans le checkAuthenticationStatus() renvoyé une valeur réelle), alors nous montons le PostAuthNavigator . 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é :

Appuyez sur le bouton de retour après vous être connecté à l'application.

Voici ce qui se passe lorsque vous appuyez sur le bouton de retour après vous être déconnecté :

Appuyez sur le bouton de retour après vous être déconnecté de l'application.

Voici quelques comportements différents que nous remarquons lors de l'utilisation de ce modèle dans notre changement de pile de navigation :

  1. Vous remarquerez qu'il n'y avait nulle part besoin d'utiliser navigation.navigate() ou navigation.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.
  2. 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.