Manejo del montaje y desmontaje de rutas de navegación en React Native
Publicado: 2022-03-10En este artículo, vamos a recorrer el montaje y desmontaje de rutas de navegación en React Native. Un comportamiento esperado de su aplicación es que una vez que se cumple la condición de autenticación, un nuevo conjunto de rutas de navegación está disponible solo para los usuarios registrados, mientras que las otras pantallas que se mostraban antes de la autenticación se eliminan y no se pueden volver a menos que el el usuario cierra la sesión de la aplicación.
Por seguridad en su aplicación, las rutas protegidas le brindan una forma de mostrar solo cierta información/contenido en su aplicación a usuarios específicos, mientras restringe el acceso de personas no autorizadas.
Trabajaremos con Expo para este proyecto porque nos ayudará a concentrarnos en el problema en cuestión en lugar de preocuparnos por muchas configuraciones. Se pueden seguir exactamente los mismos pasos en este artículo para una aplicación React Native simple.
Necesita cierta familiaridad con JavaScript y React Native para continuar con este tutorial. Aquí hay algunas cosas importantes con las que ya debería estar familiarizado:
- Componentes personalizados en React Native (cómo crear componentes, recibir, pasar y usar accesorios en un componente). Leer más.
- Reaccionar Navegación. Leer más.
- Navegador de pila en React Native. Leer más.
- Conocimiento básico de los componentes de React Native Core (
<View/>
,<Text/>
, etc.). Leer más. - Reaccionar
AsyncStorage
nativo. Leer más. - API de contexto. Leer más.
Configuración del proyecto y autenticación base
Si es nuevo en el uso de expo y no sabe cómo instalarlo, visite la documentación oficial. Una vez que se complete la instalación, continúe para inicializar un nuevo proyecto React Native con expo desde nuestro símbolo del sistema:
expo init navigation-project
Se le presentarán algunas opciones para elegir cómo desea que sea la configuración base:
En nuestro caso, seleccionemos la primera opción para configurar nuestro proyecto como un documento en blanco. Ahora, espere hasta que se complete la instalación de las dependencias de JavaScript.
Una vez que nuestra aplicación está configurada, podemos cambiar nuestro directorio a nuestro nuevo directorio de proyectos y abrirlo en su editor de código favorito. Necesitamos instalar la biblioteca que usaremos para AsyncStorage
y nuestras bibliotecas de navegación. Dentro de su directorio de carpetas en su terminal, pegue el comando anterior y elija una plantilla (funcionaría blank
) para instalar las dependencias de nuestro proyecto.
Veamos para qué sirve cada una de estas dependencias:
- @react-native-community/async-almacenamiento
Al igual que localStorage en la web, es una API React Native para almacenar datos en un dispositivo en pares clave-valor. - @react-native-community/masked-view, react-native-screens, react-native-gesture-handle
Estas dependencias son utilidades principales que utilizan la mayoría de los navegadores para crear la estructura de navegación en la aplicación. (Lea más en Primeros pasos con la navegación de React Native). - @reaccionar-navegación/nativo
Esta es la dependencia para la navegación de React Native. - @reaccionar-navegación/pila
Esta es la dependencia para la navegación de pila en 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
Para iniciar la aplicación, use expo start
desde el directorio de la aplicación en su terminal. Una vez que se inicia la aplicación, puede usar la aplicación expo desde su teléfono móvil para escanear el código de barras y ver la aplicación, o si tiene un emulador de Android/simulador IOS, puede abrir la aplicación a través de ellos desde la herramienta de desarrollo expo que se abre en su navegador cuando inicia una aplicación de exposición. Para los ejemplos de imágenes en este artículo, usaremos Genymotions para ver nuestro resultado. Así es como se verá nuestro resultado final en Genymotions:
Estructuras de carpetas
Vamos a crear nuestra estructura de carpetas desde el principio para que nos sea más fácil trabajar con ella a medida que avanzamos:
Primero necesitamos dos carpetas:
- contexto
Esta carpeta contendrá el contexto de toda nuestra aplicación, ya que trabajaremos con la API de contexto para la gestión del estado global. - puntos de vista
Esta carpeta contendrá tanto la carpeta de navegación como las vistas de las diferentes pantallas.
Continúe y cree las dos carpetas en el directorio de su proyecto.
Dentro de la carpeta de contexto, cree una carpeta llamada authContext y cree dos archivos dentro de la carpeta authContext :
- AuthContext.js ,
- AuthState.js .
Necesitaremos estos archivos cuando comencemos a trabajar con Context API.
Ahora vaya a la carpeta de vistas que creamos y cree dos carpetas más dentro de ella, a saber:
- navegación ,
- pantallas
Ahora, aún no hemos terminado, dentro de la carpeta de pantallas , cree estas dos carpetas más:
- pantallas postauth ,
- PreAuthScreens .
Si siguió la configuración de la carpeta correctamente, así es como debería verse su estructura de carpetas en este momento:
Creando nuestra primera pantalla
Ahora vamos a crear nuestra primera pantalla y llamarla welcomeScreen.js dentro de la carpeta preAuthScreens .
preAuthScreens > pantalla de bienvenida.js
Este es el contenido de nuestro archivo 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
Esto es lo que hicimos en el bloque de código anterior:
Primero, importamos las cosas que necesitamos de la biblioteca React Native, a saber, View
, Text
, Button
, TextInput
. A continuación, creamos nuestro componente funcional WelcomeScreen
.
Notarás que StyleSheet
de React Native y lo usamos para definir estilos para nuestro encabezado y también nuestro <TextInput />
.
Por último, exportamos el componente WelcomeScreen
en la parte inferior del código.
Ahora que hemos terminado con esto, hagamos que este componente funcione como se esperaba usando el gancho useState
para almacenar los valores de las entradas y actualizar sus estados cada vez que ocurra un cambio en los campos de entrada. También importaremos el useCallback
de React, ya que lo necesitaremos más adelante para mantener una función.
Primero, mientras todavía estamos en el componente WelcomeScreen
, necesitamos importar useState
y useCallback
desde React.
import React, { useState, useCallback } from 'react';
Ahora, dentro del componente funcional WelcomeScreen
, creemos los dos estados para el correo electrónico y la contraseña, respectivamente:
... const WelcomeScreen = () => { const [email, setEmail] = useState('') const [password, setPassword] = useState('') return ( ... ) } ...
A continuación, debemos modificar nuestros campos <TextInput />
para que obtengan su valor de sus respectivos estados y actualicen su estado cuando se actualice el valor de la entrada:
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> ) } ...
En el código anterior, esto es lo que hicimos:
- Hicimos que el
value
de cada una de las entradas de texto apunte a sus respectivos estados. - Agregamos el controlador
onChangeText
a nuestras entradas de texto. Esto se activa cada vez que se ingresa o elimina un nuevo valor de los campos de entrada. - Llamamos a nuestra función
onInputChange
que acepta dos argumentos:- El
value
actual lo proporciona el controladoronChangeText
. - El setter del estado que debe actualizarse (para el primer campo de entrada, pasamos
setEmail
y el segundo,setPassword
. - Finalmente, escribimos nuestra función
onInputChange
, y nuestra función solo hace una cosa: actualiza los estados respectivos con el nuevo valor.
- El
Lo siguiente en lo que debemos trabajar es en la función onUserAuthentication()
que se llama cada vez que se hace clic en el botón para enviar el formulario.
Idealmente, el usuario ya debe haber creado una cuenta y el inicio de sesión implicará algún tipo de lógica de back-end para verificar que el usuario existe y luego asignarle un token. En nuestro caso, dado que no estamos utilizando ningún backend, crearemos un objeto que contenga el detalle de inicio de sesión de usuario correcto y luego solo autenticaremos a un usuario cuando los valores que ingresen coincidan con nuestros valores fijos del objeto de inicio de sesión de email
y password
que usaremos. crear.
Aquí está el código que necesitamos para hacer esto:
... const correctAuthenticationDetails = { email: '[email protected]', password: 'password' } const WelcomeScreen = () => { ... // This function gets called when the `AUTHENTICATE` button is clicked const onUserAuthentication = () => { if ( email !== correctAuthenticationDetails.email || password !== correctAuthenticationDetails.password ) { alert('The email or password is incorrect') return } // In here, we will handle what happens if the login details are // correct } ... return ( ... ) } ...
Una de las primeras cosas que notará en el código anterior es que definimos un detalle de correctAuthenticationDetails
(que es un objeto que contiene los detalles de inicio de sesión correctos que esperamos que proporcione un usuario) fuera del componente funcional WelcomeScreen()
.
A continuación, escribimos el contenido de la función onUserAuthentication()
y usamos una declaración condicional para verificar si el email
o la password
que se encuentran en los estados respectivos no coinciden con los que proporcionamos en nuestro objeto.
Si desea ver lo que hemos hecho hasta ahora, importe el componente WelcomeScreen en su App.js de esta manera:
Abra el archivo App.js y coloque esto, reemplace todo el código con esto:
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> ); }
Mirando de cerca el código anterior, verá que lo que hicimos fue importar el componente WelcomeScreen y luego lo usamos en la función App()
.
Así es como se ve el resultado de nuestra WelcomeScreen
de bienvenida:
Ahora que hemos terminado de crear el componente WelcomeScreen , avancemos y comencemos a trabajar con la API de contexto para administrar nuestro estado global.
¿Por qué API de contexto?
Con la API de contexto, no necesitamos instalar ninguna biblioteca adicional en ReactJS, es menos estresante de configurar y es una de las formas más populares de manejar el estado global en ReactJS. Para la gestión de estados ligeros, es una buena opción.
Creando nuestro contexto
Si recuerda, creamos una carpeta de contexto anteriormente y creamos una subcarpeta dentro de ella llamada authContext .
Ahora naveguemos al archivo AuthContext.js en la carpeta authContext y creemos nuestro contexto:
contexto > authContext > AuthContext.js
import React, { createContext } from 'react'; const AuthContext = createContext(); export default AuthContext;
El AuthContext
que acabamos de crear contiene el valor del estado de loading
y los valores del estado del userToken
de usuario. Actualmente, en el createContext
que declaramos en el bloque de código anterior, no inicializamos ningún valor predeterminado aquí, por lo que nuestro contexto actualmente no está undefined
. Un valor de ejemplo del contexto de autenticación podría ser {loading: false, userToken: 'abcd}
El archivo AuthState.js contiene nuestra lógica API de contexto y sus valores de estado. Las funciones escritas aquí se pueden llamar desde cualquier lugar de nuestra aplicación y cuando actualizan los valores en el estado, también se actualizan globalmente.
Primero, traigamos todas las importaciones que necesitaremos en este archivo:
contexto > AuthContext > AuthState.js
import React, { useState } from 'react'; import AuthContext from './AuthContext'; import AsyncStorage from '@react-native-community/async-storage';
Importamos el useState()
de ReactJS para mantener nuestros estados, importamos el archivo AuthContext que creamos anteriormente porque aquí es donde se inicializa nuestro contexto vacío para la autenticación y necesitaremos usarlo como verá más adelante mientras avanzamos. , finalmente importamos el paquete AsyncStorage
(similar a localStorage para la web).
AsyncStorage
es una API de React Native que le permite almacenar datos sin conexión en el dispositivo en una aplicación de 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;
En el bloque de código de arriba, esto es lo que hicimos:
Declaramos dos estados para
userToken
eisLoading
. El estadouserToken
se usará para almacenar el token guardado enAsyncStorage
, mientras que el estadoisLoading
se usará para rastrear el estado de carga (inicialmente se establece entrue
). Descubriremos más sobre el uso de estos dos estados a medida que avancemos.A continuación, escribimos nuestra función
onAuthentication()
. Esta función es una funciónasync
que se llama cuando se hace clic en el botón de inicio de sesión desde el archivowelcomeScreen.jsx
. Esta función solo se llamará si el correo electrónico y la contraseña que el usuario proporcionó coinciden con el objeto de detalles de usuario correcto que proporcionamos. Por lo general, lo que sucede durante la autenticación es que se genera un token para el usuario después de que el usuario se autentica en el backend mediante un paquete como JWT, y este token se envía al frontend. Como no vamos a entrar en todo eso en este tutorial, creamos un token estático y lo guardamos en una variable llamadaUSER_TOKEN
.A continuación, usamos la palabra clave
await
para establecer nuestro token de usuario en AsyncStorage con el nombreuser-token
. La instrucciónconsole.warn()
solo se usa para verificar que todo salió bien, puede quitarla cuando lo desee.Finalmente, pasamos nuestra función
onAuthenticated
como un valor dentro de nuestro<AuthContext.Provider>
para que podamos acceder y llamar a la función desde cualquier lugar de nuestra aplicación.
pantallas > autenticación previa > pantalla de bienvenida.js
Primero, importe useContext
desde ReactJS e importe el AuthContext
desde el archivo AuthContext.js
.
import React, { useState, useContext } from 'react'; import AuthContext from '../../../context/authContext/AuthContext' ...
Ahora, dentro del componente funcional welcomeScreen()
, usemos el contexto que hemos creado:
... 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 ( ... ) } ...
En el bloque de código anterior, desestructuramos la función onAuthentication
de nuestro AuthContext
y luego la llamamos dentro de nuestra función onUserAuthentication()
y eliminamos la instrucción console.log()
que estaba allí antes.
En este momento, esto arrojará un error porque aún no tenemos acceso al AuthContext
. Para usar AuthContext
en cualquier parte de su aplicación, debemos envolver el archivo de nivel superior en nuestra aplicación con AuthState
(en nuestro caso, es el archivo App.js ).
Vaya al archivo App.js y reemplace el código allí con esto:
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> ); }
Hemos llegado hasta aquí y hemos terminado con esta sección. Antes de pasar a la siguiente sección donde configuramos nuestro enrutamiento, creemos una nueva pantalla. La pantalla que estamos a punto de crear será el archivo HomeScreen.js que se supone que aparecerá solo después de una autenticación exitosa.
Vaya a: pantallas > postAuth .
Cree un nuevo archivo llamado HomeScreen.js . Aquí está el código para el archivo HomeScreen.js :
pantallas > 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
Por ahora, el botón de cierre de sesión tiene una instrucción console.log()
ficticia. Más adelante, crearemos la funcionalidad de cierre de sesión y la pasaremos a la pantalla desde nuestro contexto.
Configuración de nuestras rutas
Necesitamos crear tres (3) archivos dentro de nuestra carpeta de navegación:
- postAuthNavigator.js ,
- preAuthNavigator.js ,
- AppNavigator.js .
Una vez que haya creado estos tres archivos, navegue hasta el archivo preAuthNaviagtor.js que acaba de crear y escriba esto:
navegación > 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;
En el archivo de arriba, esto es lo que hicimos:
- Importamos el
createStackNavigator
de@react-navigation/stack
que estamos usando para nuestra navegación de pila. ElcreateStackNavigator
proporciona una forma para que su aplicación haga la transición entre pantallas donde cada nueva pantalla se coloca encima de una pila. De forma predeterminada, el navegador de pila está configurado para tener el aspecto familiar de iOS y Android: las nuevas pantallas se deslizan desde la derecha en iOS, se desvanecen desde la parte inferior en Android. Haga clic aquí si desea obtener más información sobre el navegador de pila en React Native. - Desestructuramos
Navigator
yScreen
desdecreateStackNavigator()
. - En nuestra declaración de devolución, creamos nuestra navegación con
<Navigator/>
y creamos nuestra pantalla con<Screen/>
. esto significa que si tuviéramos múltiples pantallas a las que se puede acceder antes de la autenticación, tendremos múltiples etiquetas<Screen/>
aquí representándolas. - Finalmente, exportamos nuestro componente
PreAuthNavigator
.
Hagamos algo similar para el archivo postAuthNavigator.js
.
navegación > 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;
Como vemos en el código anterior, la única diferencia entre preAuthNavigator.js y postAuthNavigator.js es la pantalla que se representa. Mientras que el primero toma la pantalla de bienvenida, el WelcomeScreen
toma la pantalla de HomeScreen
.
Para crear nuestro AppNavigator.js necesitamos crear algunas cosas.
Dado que AppNavigator.js es donde cambiaremos y verificaremos qué ruta estará disponible para el acceso del usuario, necesitamos varias pantallas para que esto funcione correctamente, describamos las cosas que debemos crear primero:
- TransitionScreen.js
Mientras la aplicación decide qué navegación va a montar, queremos que aparezca una pantalla de transición. Por lo general, la pantalla de transición será una rueda giratoria de carga o cualquier otra animación personalizada elegida para la aplicación, pero en nuestro caso, usaremos una etiqueta básica<Text/>
para mostrar laloading…
. -
checkAuthenticationStatus()
Esta función es la que llamaremos para verificar el estado de autenticación que determinará qué pila de navegación se montará. Crearemos esta función en nuestro contexto y la usaremos en Appnavigator.js .
Ahora, avancemos y creemos nuestro archivo TransitionScreen.js .
pantallas > TransitionScreen.js
import React from 'react'; import { Text, View } from 'react-native'; const TransitionScreen = () => { return ( <View> <Text>Loading...</Text> </View> ) } export default TransitionScreen
Nuestra pantalla de transición es solo una pantalla simple que muestra el texto de carga. Veremos dónde usar esto a medida que avancemos en este artículo.
A continuación, vayamos a nuestro AuthState.js y escribamos nuestro checkAuthenticationStatus()
:
contexto > 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;
En el bloque de código anterior, escribimos la función checkAuthenticationStatus()
. En nuestra función, esto es lo que estamos haciendo:
- Usamos la palabra clave
await
para obtener nuestro token deAsyncStorage
. ConAsyncStorage
, si no se proporciona ningún token, devuelvenull
. Nuestro estado inicialuserToken
de usuario también se establece ennull
. - Usamos
setUserToken
para establecer nuestro valor devuelto porAsyncStorage
como nuestro nuevouserToken
de usuario. Si el valor devuelto esnull
, significa que nuestrouserToken
sigue siendonull
. - Después del bloque
try{}…catch(){}
, establecemosisLoading
en falso porque la función para verificar el estado de autenticación está completa. Necesitaremos el valor deisLoading
para saber si aún deberíamos mostrar la pantalla deTransitionScreen
o no. Vale la pena considerar configurar un error si hay un error al recuperar el token para que podamos mostrarle al usuario un botón "Reintentar" o "Intentar de nuevo" cuando se encuentre el error. - Cada vez que se monta
AuthState
, queremos verificar el estado de autenticación, por lo que usamos eluseEffect()
ReactJS para hacer esto. Llamamos a nuestra funcióncheckAuthenticationStatus()
dentro deluseEffect()
y establecemos el valor deisLoading
enfalse
cuando haya terminado. - Finalmente, agregamos nuestros estados a nuestros
<AuthContext.Provider/>
para que podamos acceder a ellos desde cualquier parte de nuestra aplicación cubierta por la API de contexto.
Ahora que tenemos nuestra función, es hora de volver a nuestro AppNavigator.js y escribir el código para montar un navegador de pila particular basado en el estado de autenticación:
navegación > AppNavigator.js
Primero, importaremos todo lo que necesitamos para nuestro 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";
Ahora que tenemos todas nuestras importaciones, creemos la función AppNavigator()
.
... const AppNavigator = () => { } export default AppNavigator
A continuación, continuaremos escribiendo el contenido de nuestra función 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
En el bloque de código anterior, aquí hay un resumen de lo que hicimos:
- Creamos un navegador de pila y desestructuramos el
Navigator
y laScreen
a partir de él. - Importamos el
isLoading
userToken
nuestroAuthContext
- Cuando se monta
AuthState
, se llama acheckAuthenticationStatus()
en el ganchouseEffecct
allí. Usamos la declaraciónif
para verificar siisLoading
estrue
, si estrue
, la pantalla que devolvemos es nuestra<TransitionScreen />
que creamos anteriormente porque la funcióncheckAuthenticationStatus()
aún no está completa. - Una vez que nuestro
checkAuthenticationStatus()
está completo,isLoading
se establece enfalse
y devolvemos nuestros componentes principales de navegación. - El
NavigationContainer
se importó desde@react-navigation/native
. Solo se usa una vez en el navegador principal de nivel superior. Tenga en cuenta que no estamos usando esto en preAuthNavigator.js o postAuthNavigator.js. - En nuestro
AppNavigator()
, todavía creamos un navegador de pila. Si eluserToken
de usuario obtenido de nuestra API de contexto esnull
,PreAuthNavigator
, si su valor es otro (lo que significa queAsyncStorage.getItem()
encheckAuthenticationStatus()
devolvió un valor real), entoncesPostAuthNavigator
. Nuestra representación condicional se realiza mediante el operador ternario.
Ahora hemos configurado nuestro AppNavigator.js . A continuación, debemos pasar nuestro AppNavigator
a nuestro archivo App.js.
Pasemos nuestro AppNavigator
al archivo App.js :
Aplicación.js
... import AppNavigator from './views/navigation/AppNavigator'; ... return ( <AuthState> <AppNavigator /> </AuthState> );
Veamos ahora cómo se ve nuestra aplicación en este momento:
Esto es lo que sucede cuando proporciona una credencial incorrecta al intentar iniciar sesión:
Adición de la funcionalidad de cierre de sesión
En este punto, nuestro proceso de autenticación y selección de ruta está completo. Lo único que queda para nuestra aplicación es agregar la funcionalidad de cierre de sesión.
El botón de cierre de sesión está en el archivo HomeScreen.js . Pasamos una función onLogout()
al atributo onPress
del botón. Por ahora, tenemos una simple instrucción console.log()
en nuestra función, pero eso cambiará dentro de poco.
Ahora, vayamos a nuestro AuthState.js y escribamos la función para cerrar sesión. Esta función simplemente borra AsyncStorage
donde se guarda el token de usuario.
contexto > authContext > AuthState.js
... const AuthState = (props) => { ... const userSignout = async() => { await AsyncStorage.removeItem('user-token'); setUserToken(null); } return ( ... ) } export default AuthState;
userSignout()
es una función asíncrona que elimina el user-token
de nuestro AsyncStorage
.
Ahora debemos llamar a la función userSignout()
en nuestro HomeScreen.js cada vez que se haga clic en el botón de cierre de sesión.
Vayamos a nuestro HomeScreen.js y usemos userSignout()
de nuestro AuthContext
.
pantallas > 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> ) } ...
En el bloque de código anterior, importamos el gancho useContext
de ReactJS, luego importamos nuestro AuthContext. A continuación, desestructuramos la función userSignout
de nuestro AuthContext
y esta función userSignout()
se llama en nuestra función onLogout()
.
Ahora, cada vez que se hace clic en nuestro botón de cierre de sesión, se borra el token de usuario en nuestro AsyncStorage
.
¡Voila! todo nuestro proceso ha terminado.
Esto es lo que sucede cuando presiona el botón Atrás después de iniciar sesión:
Esto es lo que sucede cuando presiona el botón Atrás después de cerrar la sesión:
Aquí hay algunos comportamientos diferentes que notamos cuando usamos este patrón en nuestro cambio de pila de navegación:
- Notará que no había ningún lugar en el que necesitáramos hacer uso de
navigation.navigate()
onavigation.push()
para ir a otra ruta después de iniciar sesión. Una vez que nuestro estado se actualiza con el token de usuario, la pila de navegación representada cambia automáticamente. - Al presionar el botón Atrás en su dispositivo después de que el inicio de sesión se haya realizado correctamente, no puede regresar a la página de inicio de sesión, sino que cierra la aplicación por completo. Este comportamiento es importante porque no desea que el usuario pueda volver a la página de inicio de sesión a menos que cierre sesión en la aplicación. Lo mismo se aplica al cierre de sesión: una vez que el usuario cierra sesión, no puede usar el botón Atrás para volver a la pantalla de
HomeScreen
, sino que la aplicación se cierra.
Conclusión
En muchas aplicaciones, la autenticación es una de las partes más importantes porque confirma que la persona que intenta acceder al contenido protegido tiene derecho a acceder a la información. Aprender a hacerlo bien es un paso importante en la creación de una aplicación excelente, intuitiva y fácil de usar/navegar.
Sobre la base de este código, aquí hay algunas cosas que podría considerar agregar:
- Validación de formularios para validar campos de entrada. Consulte la validación de formularios React Native con Formik y Yup.
- Autenticación de Firebase para integrar la autenticación con Gmail, Github, Facebook, Twitter o su interfaz personalizada. Echa un vistazo a React Native Firebase.
- Conceptos de código para diseñadores: autenticación y autorización.
Aquí también hay algunos recursos importantes que encontré que lo iluminarán más sobre la autenticación, la seguridad y cómo hacerlo bien:
Recursos
- React Native: flujo de autenticación de usuario explicado
- 10 mejores prácticas de seguridad de React
- Métodos de autenticación que pueden prevenir la próxima infracción
- Vea una compilación/vista previa en vivo de nuestra aplicación aquí;
- Ver el proyecto en GitHub.