Manipularea montajului și demontării rutelor de navigație în React Native
Publicat: 2022-03-10În acest articol, vom parcurge montarea și demontarea rutelor de navigație în React Native. Un comportament așteptat al aplicației dvs. este că, odată ce condiția de autentificare este îndeplinită, un nou set de rute de navigare este disponibil numai pentru utilizatorii conectați, în timp ce celelalte ecrane care au fost afișate înainte de autentificare sunt eliminate și nu pot fi returnate decât dacă utilizatorul se deconectează de la aplicație.
Pentru securitatea aplicației dvs., rutele protejate vă oferă o modalitate de a afișa numai anumite informații/conținut din aplicație anumitor utilizatori, restricționând în același timp accesul persoanelor neautorizate.
Vom lucra cu Expo pentru acest proiect, deoarece ne va ajuta să ne concentrăm asupra problemei în cauză în loc să ne facem griji pentru o mulțime de setări. Aceiași pași din acest articol ar putea fi urmați pentru o aplicație React Native.
Aveți nevoie de puțină familiaritate cu JavaScript și React Native pentru a continua acest tutorial. Iată câteva lucruri importante cu care ar trebui să fii deja familiarizat:
- Componente personalizate în React Native (cum să creați componente, să primiți, să transmiteți și să utilizați elemente de recuzită într-o componentă). Citeste mai mult.
- React Navigation. Citeste mai mult.
- Stack Navigator în React Native. Citeste mai mult.
- Cunoștințe de bază despre componentele React Native Core (
<View/>
,<Text/>
, etc.). Citeste mai mult. - React Native
AsyncStorage
. Citeste mai mult. - Context API. Citeste mai mult.
Configurarea proiectului și autentificarea de bază
Dacă sunteți nou în utilizarea expo și nu știți cum să instalați expo, vizitați documentația oficială. Odată ce instalarea este finalizată, continuați să inițializați un nou proiect React Native cu expo din promptul nostru de comandă:
expo init navigation-project
Vi se vor prezenta câteva opțiuni pentru a alege cum doriți să fie configurația de bază:
În cazul nostru, să selectăm prima opțiune pentru a configura proiectul nostru ca document gol. Acum, așteptați până când instalarea dependențelor JavaScript este completă.
Odată ce aplicația noastră este configurată, ne putem schimba directorul în noul director de proiect și îl putem deschide în editorul de cod preferat. Trebuie să instalăm biblioteca pe care o vom folosi pentru AsyncStorage
și bibliotecile noastre de navigare. În directorul folderului din terminalul dvs., lipiți comanda de mai sus și alegeți un șablon (un blank
ar funcționa) pentru a instala dependențele de proiect.
Să ne uităm la ce este fiecare dintre aceste dependențe:
- @react-native-community/async-storage
La fel ca localStorage pe web, este un API React Native pentru păstrarea datelor pe un dispozitiv în perechi cheie-valoare. - @react-native-community/masked-view, react-native-screens, react-native-gesture-handle
Aceste dependențe sunt utilități de bază care sunt utilizate de majoritatea navigatorilor pentru a crea structura de navigare în aplicație. (Citiți mai multe în Noțiuni introductive cu navigarea React Native.) - @react-navigation/native
Aceasta este dependența pentru navigarea React Native. - @react-navigation/stiva
Aceasta este dependența pentru navigarea stivei în 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
Pentru a porni aplicația, utilizați expo start
din directorul aplicației din terminalul dvs. Odată ce aplicația este pornită, puteți utiliza aplicația expo de pe telefonul mobil pentru a scana codul de bare și a vizualiza aplicația, sau dacă aveți un emulator Android/simulator IOS, puteți deschide aplicația prin intermediul acestora din instrumentul de dezvoltare expo care se deschide în browser când porniți o aplicație expo. Pentru exemplele de imagini din acest articol, vom folosi Genymotions pentru a vedea rezultatul nostru. Iată cum va arăta rezultatul nostru final în Genymotions:
Structuri de foldere
Să ne creăm structura de foldere de la început, astfel încât să ne fie mai ușor să lucrăm cu ea pe măsură ce procedăm:
Avem nevoie de două foldere mai întâi:
- context
Acest folder va păstra contextul pentru întreaga noastră aplicație, deoarece vom lucra cu Context API pentru gestionarea globală a stării. - vederi
Acest folder va deține atât folderul de navigare, cât și vizualizările pentru diferite ecrane.
Continuați și creați cele două foldere în directorul proiectului.
În folderul context, creați un folder numit authContext și creați două fișiere în interiorul folderului authContext :
- AuthContext.js ,
- AuthState.js .
Vom avea nevoie de aceste fișiere când vom începe să lucrăm cu Context API.
Acum mergeți la folderul de vizualizări pe care l-am creat și creați încă două foldere în interiorul acestuia, și anume:
- navigatie ,
- ecrane .
Acum, nu am terminat încă, în folderul ecrane , creați încă două foldere:
- postAuthScreens ,
- preAuthScreens .
Dacă ați urmat corect configurarea folderului, așa ar trebui să arate structura dvs. de folder în acest moment:
Crearea primului nostru ecran
Acum să creăm primul nostru ecran și să-l numim welcomeScreen.js în folderul preAuthScreens .
preAuthScreens > welcomeScreen.js
Iată conținutul fișierului nostru 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
Iată ce am făcut în blocul de cod de mai sus:
Mai întâi, am importat lucrurile de care avem nevoie din biblioteca React Native, și anume, View
, Text
, Button
, TextInput
. Apoi, am creat componenta noastră funcțională WelcomeScreen
.
Veți observa că am importat StyleSheet
din React Native și am folosit-o pentru a defini stiluri pentru antetul nostru și, de asemenea, pentru <TextInput />
.
În cele din urmă, exportăm componenta WelcomeScreen
din partea de jos a codului.
Acum că am terminat cu asta, să facem ca această componentă să funcționeze așa cum era de așteptat, folosind cârligul useState
pentru a stoca valorile intrărilor și a le actualiza stările ori de câte ori are loc o modificare în câmpurile de intrare. Vom aduce și importul useCallback
hook de la React, deoarece vom avea nevoie de el mai târziu pentru a menține o funcție.
În primul rând, în timp ce suntem încă în componenta WelcomeScreen
, trebuie să importam useState
și useCallback
din React.
import React, { useState, useCallback } from 'react';
Acum, în interiorul componentei funcționale WelcomeScreen
, să creăm cele două stări pentru e-mail și respectiv parolă:
... const WelcomeScreen = () => { const [email, setEmail] = useState('') const [password, setPassword] = useState('') return ( ... ) } ...
În continuare, trebuie să ne modificăm câmpurile <TextInput />
astfel încât să-și obțină valoarea din stările respective și să-și actualizeze starea atunci când valoarea intrării este actualizată:
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> ) } ...
În codul de mai sus, iată ce am făcut:
- Am făcut ca
value
fiecărei intrări de text să indice stările lor respective. - Am adăugat handlerul
onChangeText
la intrările noastre de text. Aceasta se declanșează de fiecare dată când o nouă valoare este introdusă sau ștearsă din câmpurile de intrare. - Am numit funcția noastră
onInputChange
care acceptă două argumente:-
value
curentă este furnizată de handler-ulonChangeText
. - Setter-ul stării care ar trebui actualizat (pentru primul câmp de intrare trecem
setEmail
și al doilea trecemsetPassword
. - În cele din urmă, scriem funcția noastră
onInputChange
, iar funcția noastră face un singur lucru: actualizează stările respective cu noua valoare.
-
Următorul lucru la care trebuie să lucrăm este funcția onUserAuthentication()
cu care este apelată de fiecare dată când se face clic pe butonul pentru trimiterea formularului.
În mod ideal, utilizatorul trebuie să-și fi creat deja un cont, iar autentificarea va implica o logică de tip backend pentru a verifica dacă utilizatorul există și apoi a atribui un token utilizatorului. În cazul nostru, deoarece nu folosim niciun backend, vom crea un obiect care conține detaliile corecte de conectare a utilizatorului și apoi vom autentifica un utilizator numai atunci când valorile pe care le introduce se potrivesc cu valorile noastre fixe din obiectul de conectare al e- email
și al password
pe care le vom autentifica. crea.
Iată codul de care avem nevoie pentru a face asta:
... 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 ( ... ) } ...
Unul dintre primele lucruri pe care le veți observa în codul de mai sus este că am definit un correctAuthenticationDetails
(care este un obiect care deține detaliile de conectare corecte pe care ne așteptăm să le furnizeze utilizatorul) în afara componentei funcționale WelcomeScreen()
.
Apoi, am scris conținutul funcției onUserAuthentication()
și am folosit o declarație condiționată pentru a verifica dacă e- email
sau password
deținute în statele respective nu se potrivește cu cea pe care am furnizat-o în obiectul nostru.
Dacă doriți să vedeți ce am făcut până acum, importați componenta WelcomeScreen în App.js astfel:
Deschideți fișierul App.js și puneți acesta înlocuiți întregul cod cu acesta:
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> ); }
Privind îndeaproape codul de mai sus, veți vedea că ceea ce am făcut a fost să importam componenta WelcomeScreen și apoi să o folosim în funcția App()
.
Iată cum arată rezultatul WelcomeScreen
nostru de bun venit:
Acum că am terminat de construit componenta WelcomeScreen , să mergem mai departe și să începem să lucrăm cu Context API pentru a gestiona starea noastră globală.
De ce Context API?
Folosind Context API, nu este nevoie să instalăm nicio bibliotecă suplimentară în ReactJS, este mai puțin stresant de configurat și este una dintre cele mai populare moduri de a gestiona starea globală în ReactJS. Pentru gestionarea ușoară a stării, este o alegere bună.
Crearea contextului nostru
Dacă vă amintiți, am creat mai devreme un folder de context și am creat un subdosar în interiorul acestuia numit authContext .
Acum să navigăm la fișierul AuthContext.js din folderul authContext și să creăm contextul nostru:
context > authContext > AuthContext.js
import React, { createContext } from 'react'; const AuthContext = createContext(); export default AuthContext;
AuthContext
pe care tocmai l-am creat deține valoarea stării de loading
și valorile stării userToken
. În prezent, în createContext
pe care l-am declarat în blocul de cod de mai sus, nu am inițializat nicio valoare implicită aici, așa că contextul nostru este momentan undefined
. Un exemplu de valoare a contextului de autentificare ar putea fi {loading: false, userToken: 'abcd}
Fișierul AuthState.js deține logica noastră Context API și valorile de stare ale acestora. Funcțiile scrise aici pot fi apelate de oriunde în aplicația noastră și atunci când actualizează valorile în stare, este actualizată și la nivel global.
Mai întâi, să aducem toate importurile de care vom avea nevoie în acest fișier:
context > AuthContext > AuthState.js
import React, { useState } from 'react'; import AuthContext from './AuthContext'; import AsyncStorage from '@react-native-community/async-storage';
Am importat cârligul useState()
din ReactJS pentru a ne păstra stările, am importat fișierul AuthContext pe care l-am creat mai sus, deoarece aici este inițializat contextul nostru gol pentru autentificare și va trebui să-l folosim așa cum veți vedea mai târziu în timp ce progresăm. , în cele din urmă importăm pachetul AsyncStorage
(similar cu localStorage pentru web).
AsyncStorage
este un API React Native care vă permite să păstrați datele offline pe dispozitiv într-o aplicație 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;
În blocul de cod de mai sus, iată ce am făcut:
Am declarat două stări pentru
userToken
șiisLoading
. StareauserToken
va fi folosită pentru a stoca simbolul salvat înAsyncStorage
, în timp ce stareaisLoading
va fi folosită pentru a urmări starea de încărcare (inițial este setată latrue
). Vom afla mai multe despre utilizarea acestor două stări pe măsură ce procedăm.Apoi, am scris funcția noastră
onAuthentication()
. Această funcție este o funcțieasync
care este apelată atunci când se face clic pe butonul de conectare din fișierulwelcomeScreen.jsx
. Această funcție va fi apelată numai dacă e-mailul și parola pe care utilizatorul le-a furnizat se potrivesc cu obiectul corect pentru detaliile utilizatorului pe care l-am furnizat. De obicei, ceea ce se întâmplă în timpul autentificării este că un token este generat pentru utilizator după ce utilizatorul este autentificat pe backend folosind un pachet precum JWT, iar acest token este trimis către front-end. Deoarece nu vom aborda toate acestea pentru acest tutorial, am creat un token static și l-am păstrat într-o variabilă numităUSER_TOKEN
.Apoi, folosim cuvântul cheie
await
pentru a seta simbolul de utilizator la AsyncStorage cu numeleuser-token
. Declarațiaconsole.warn()
este folosită doar pentru a verifica dacă totul a mers bine, o puteți scoate oricând doriți.În cele din urmă, transmitem funcția noastră
onAuthenticated
ca valoare în interiorul<AuthContext.Provider>
, astfel încât să putem accesa și apela funcția de oriunde în aplicația noastră.
ecrane > preAuth > welcomeScreen.js
Mai întâi, importați useContext
din ReactJS și importați AuthContext
din fișierul AuthContext.js
.
import React, { useState, useContext } from 'react'; import AuthContext from '../../../context/authContext/AuthContext' ...
Acum, în interiorul componentei funcționale welcomeScreen()
, să folosim contextul pe care l-am creat:
... 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 ( ... ) } ...
În blocul de cod de mai sus, am destructurat funcția onAuthentication
din AuthContext
și apoi am numit-o în cadrul funcției noastre onUserAuthentication()
și am eliminat instrucțiunea console.log()
care era acolo până acum.
În acest moment, aceasta va genera o eroare, deoarece nu avem încă acces la AuthContext
. Pentru a utiliza AuthContext
oriunde în aplicația dvs., trebuie să împachetăm fișierul de nivel superior din aplicația noastră cu AuthState
(în cazul nostru, este fișierul App.js ).
Accesați fișierul App.js și înlocuiți codul de acolo cu acesta:
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> ); }
Am ajuns atât de departe și am terminat cu această secțiune. Înainte de a trece la următoarea secțiune în care ne-am configurat rutarea, să creăm un nou ecran. Ecranul pe care urmează să îl creăm va fi fișierul HomeScreen.js care ar trebui să apară numai după autentificarea cu succes.
Accesați: ecrane > postAuth .
Creați un fișier nou numit HomeScreen.js . Iată codul pentru fișierul HomeScreen.js :
ecrane > 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
Deocamdată, butonul de deconectare are o instrucțiune falsă console.log()
. Mai târziu, vom crea funcționalitatea de deconectare și o vom trece pe ecran din contextul nostru.
Configurarea rutelor noastre
Trebuie să creăm trei (3) fișiere în folderul nostru de navigare:
- postAuthNavigator.js ,
- preAuthNavigator.js ,
- AppNavigator.js .
După ce ați creat aceste trei fișiere, navigați la fișierul preAuthNaviagtor.js pe care tocmai l-ați creat și scrieți asta:
navigare > 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;
În fișierul de mai sus, iată ce am făcut:
- Am importat
createStackNavigator
din@react-navigation/stack
pe care îl folosim pentru navigarea în stivă.createStackNavigator
Oferă o modalitate prin care aplicația dvs. să facă tranziția între ecrane în care fiecare ecran nou este plasat deasupra unei stive. În mod implicit, navigatorul de stivă este configurat pentru a avea aspectul și senzația familiar iOS și Android: ecranele noi glisează din dreapta pe iOS, se estompează de jos pe Android. Faceți clic aici dacă doriți să aflați mai multe despre navigatorul de stivă din React Native. - Am destructurat
Navigator
șiScreen
dincreateStackNavigator()
. - În declarația de returnare, ne-am creat navigarea cu
<Navigator/>
și ne-am creat ecranul cu<Screen/>
. aceasta înseamnă că dacă am avut mai multe ecrane care pot fi accesate înainte de autentificare, vom avea mai multe etichete<Screen/>
aici reprezentându-le. - În cele din urmă, exportăm componenta noastră
PreAuthNavigator
.
Să facem un lucru similar pentru fișierul postAuthNavigator.js
.
navigare > 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;
După cum vedem în codul de mai sus, singura diferență între preAuthNavigator.js și postAuthNavigator.js este afișarea ecranului. În timp ce primul primește ecranul de bun venit, WelcomeScreen
preia ecranul HomeScreen
pornire .
Pentru a crea AppNavigator.js , trebuie să creăm câteva lucruri.
Deoarece AppNavigator.js este locul în care vom comuta și vom verifica ce rută va fi disponibilă pentru acces de către utilizator, avem nevoie de mai multe ecrane pentru ca acest lucru să funcționeze corect, să subliniem lucrurile pe care trebuie să le creăm mai întâi:
- TransitionScreen.js
În timp ce aplicația decide ce navigație va monta, dorim să apară un ecran de tranziție. De obicei, ecranul de tranziție va fi un rotisor de încărcare sau orice altă animație personalizată aleasă pentru aplicație, dar în cazul nostru, vom folosi o etichetă de bază<Text/>
pentru a afișaloading…
. -
checkAuthenticationStatus()
Această funcție este ceea ce vom apela pentru a verifica starea de autentificare, care va determina ce stivă de navigare va fi montată. Vom crea această funcție în contextul nostru și o vom folosi în Appnavigator.js .
Acum, să mergem mai departe și să creăm fișierul nostru TransitionScreen.js .
ecrane > TransitionScreen.js
import React from 'react'; import { Text, View } from 'react-native'; const TransitionScreen = () => { return ( <View> <Text>Loading...</Text> </View> ) } export default TransitionScreen
Ecranul nostru de tranziție este doar un ecran simplu care arată textul de încărcare. Vom vedea unde să folosim acest lucru pe măsură ce procedăm în acest articol.
Apoi, să mergem la AuthState.js și să scriem checkAuthenticationStatus()
:
context > authContext > AuthState.js
import React, { useState, useEffect } from 'react'; import AuthContext from './AuthContext'; import AsyncStorage from '@react-native-community/async-storage'; const AuthState = (props) => { const [userToken, setUserToken] = useState(null); const [isLoading, setIsLoading] = useState(true); ... useEffect(() => { checkAuthenticationStatus() }, []) const checkAuthenticationStatus = async () => { try { const returnedToken = await AsyncStorage.getItem('user-toke n'); setUserToken(returnedToken); console.warn('User token set to the state value) } catch(err){ console.warn(`Here's the error that occured while retrievin g token: ${err}`) } setIsLoading(false) } const onAuthentication = async() => { ... } return ( <AuthContext.Provider value={{ onAuthentication, userToken, isLoading, }} > {props.children} </AuthContext.Provider> ) } export default AuthState;
În blocul de cod de mai sus, am scris funcția checkAuthenticationStatus()
. În funcția noastră, iată ce facem:
- Am folosit cuvântul cheie
await
pentru a obține indicativul nostru de laAsyncStorage
. CuAsyncStorage
, dacă nu este furnizat niciun simbol, acesta returneazănull
. De asemenea, starea noastră inițialăuserToken
este setată lanull
. - Folosim
setUserToken
pentru a seta valoarea returnată de laAsyncStorage
ca noul nostruuserToken
. Dacă valoarea returnată estenull
, înseamnă căuserToken
-ul nostru rămânenull
. - După blocul
try{}…catch(){}
, setămisLoading
la false deoarece funcția de verificare a stării de autentificare este completă. Vom avea nevoie de valoareaisLoading
pentru a ști dacă ar trebui să afișăm în continuareTransitionScreen
sau nu. Merită să luați în considerare setarea unei erori dacă există o eroare la preluarea jetonului, astfel încât să putem arăta utilizatorului un buton „Reîncercați” sau „Încercați din nou” atunci când se întâlnește eroarea. - Ori de câte ori se montează
AuthState
, vrem să verificăm starea de autentificare, așa că folosimuseEffect()
ReactJS pentru a face acest lucru. Apelăm funcția noastrăcheckAuthenticationStatus()
în interiorul cârliguluiuseEffect()
și setăm valoareaisLoading
lafalse
când se termină. - În cele din urmă, adăugăm stările noastre la valorile noastre
<AuthContext.Provider/>
, astfel încât să le putem accesa de oriunde în aplicația noastră acoperită de API-ul Context.
Acum că avem funcția noastră, este timpul să ne întoarcem la AppNavigator.js și să scriem codul pentru montarea unui anumit navigator de stivă pe baza stării de autentificare:
navigare > AppNavigator.js
În primul rând, vom importa tot ce avem nevoie pentru 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";
Acum că avem toate importurile noastre, să creăm funcția AppNavigator()
.
... const AppNavigator = () => { } export default AppNavigator
În continuare, vom continua să scriem conținutul funcției noastre 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
În blocul de cod de mai sus, iată o schiță a ceea ce am făcut:
- Am creat un navigator de stivă și am destructurat
Navigator
șiScreen
din acesta. - Am importat
userToken
-ul șiisLoading
dinAuthContext
- Când se montează
AuthState
,checkAuthenticationStatus()
este apelat în hook-uluseEffecct
de acolo. Folosim instrucțiuneaif
pentru a verifica dacăisLoading
estetrue
, dacă estetrue
, ecranul pe care îl returnăm este<TransitionScreen />
pe care l-am creat mai devreme deoarece funcțiacheckAuthenticationStatus()
nu este încă completă. - Odată ce
checkAuthenticationStatus()
este complet,isLoading
este setat lafalse
și returnăm componentele noastre principale de navigare. -
NavigationContainer
a fost importat din@react-navigation/native
. Este folosit o singură dată în navigatorul principal de nivel superior. Observați că nu folosim acest lucru în preAuthNavigator.js sau în postAuthNavigator.js. - În
AppNavigator()
, creăm în continuare un navigator de stivă. DacăuserToken
-ul obținut din API-ul nostru Context estenull
,PreAuthNavigator
, dacă valoarea lui este altceva (înseamnă căAsyncStorage.getItem()
dincheckAuthenticationStatus()
a returnat o valoare reală), atunci montemPostAuthNavigator
. Redarea noastră condiționată se face folosind operatorul ternar.
Acum am configurat AppNavigator.js . Apoi, trebuie să trecem AppNavigator
în fișierul nostru App.js.
Să trecem AppNavigator
în fișierul App.js :
App.js
... import AppNavigator from './views/navigation/AppNavigator'; ... return ( <AuthState> <AppNavigator /> </AuthState> );
Să vedem acum cum arată aplicația noastră în acest moment:
Iată ce se întâmplă când furnizați o autentificare incorectă în timp ce încercați să vă conectați:
Adăugarea funcției de deconectare
În acest moment, procesul nostru de autentificare și selecție a rutei este finalizat. Singurul lucru rămas pentru aplicația noastră este să adăugați funcționalitatea de deconectare.
Butonul de deconectare se află în fișierul HomeScreen.js . Am transmis o onLogout()
atributului onPress
al butonului. Pentru moment, avem o instrucțiune simplă console.log()
în funcția noastră, dar în puțin timp asta se va schimba.
Acum, să mergem la AuthState.js și să scriem funcția pentru deconectare. Această funcție pur și simplu șterge AsyncStorage
unde este salvat simbolul utilizatorului.
context > authContext > AuthState.js
... const AuthState = (props) => { ... const userSignout = async() => { await AsyncStorage.removeItem('user-token'); setUserToken(null); } return ( ... ) } export default AuthState;
userSignout()
este o funcție asincronă care elimină user-token
din AsyncStorage
.
Acum trebuie să apelăm funcția userSignout()
din HomeScreen.js de fiecare dată când se face clic pe butonul de deconectare.
Să mergem la HomeScreen.js și să folosim userSignout userSignout()
din AuthContext
.
ecrane > 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> ) } ...
În blocul de cod de mai sus, am importat cârligul useContext
din ReactJS, apoi am importat AuthContext. Apoi, am destructurat funcția userSignout
din AuthContext
și această userSignout()
este apelată în funcția noastră onLogout()
.
Acum, de fiecare dată când se face clic pe butonul nostru de deconectare, simbolul utilizatorului din AsyncStorage
este șters.
Voila! întregul nostru proces este încheiat.
Iată ce se întâmplă când apăsați butonul Înapoi după ce v-ați conectat:
Iată ce se întâmplă când apăsați butonul Înapoi după deconectare:
Iată câteva comportamente diferite pe care le observăm când folosim acest model în comutarea stivei de navigare:
- Veți observa că nu era nici un loc de care trebuia să folosim
navigation.navigate()
saunavigation.push()
pentru a merge la o altă rută după autentificare. Odată ce starea noastră este actualizată cu simbolul utilizatorului, stiva de navigare redată este schimbată automat. - Apăsarea butonului Înapoi de pe dispozitiv după ce autentificarea a reușit nu vă poate duce înapoi la pagina de conectare, în schimb, aceasta închide aplicația complet. Acest comportament este important deoarece nu doriți ca utilizatorul să se poată întoarce înapoi la pagina de conectare, cu excepția cazului în care se deconectează din aplicație. Același lucru este valabil și pentru deconectare - odată ce utilizatorul se deconectează, nu poate folosi butonul înapoi pentru a reveni la ecranul
HomeScreen
, dar, în schimb, aplicația se închide.
Concluzie
În multe aplicații, autentificarea este una dintre cele mai importante părți, deoarece confirmă că persoana care încearcă să obțină acces la conținut protejat are dreptul de a accesa informațiile. A învăța cum să o faci corect este un pas important în construirea unei aplicații grozave, intuitive și ușor de utilizat/navigat.
Pe baza acestui cod, iată câteva lucruri pe care ați putea să le adăugați:
- Validare formular pentru validarea câmpurilor de intrare. Verificați validarea formularului React Native cu Formik și Yup.
- Autentificare Firebase pentru integrarea autentificării cu Gmail, Github, Facebook, Twitter sau cu interfața dvs. personalizată. Consultați React Native Firebase.
- Concepte de cod pentru designeri: Autentificare și Autorizare.
Iată, de asemenea, câteva resurse importante pe care le-am găsit, care vă vor lumina mai mult despre autentificare, securitate și cum să o faceți corect:
Resurse
- React Native: Fluxul de autentificare a utilizatorului explicat
- 10 cele mai bune practici de securitate React
- Metode de autentificare care pot preveni următoarea încălcare
- Vizualizați o versiune live/previzualizare a aplicației noastre aici;
- Vizualizați proiectul pe GitHub.