Taller React Native-H

Descargar como pdf o txt
Descargar como pdf o txt
Está en la página 1de 52

DESARROLLO DE APPS CON

REACT NATIVE

Ing. Marco León Mora Méndez


SENA - CEET
Contenido
DESARROLLO DE APPS ..................................................................................................... 4
REACT NATIVE ................................................................................................................... 5
ENTORNO DE DESARROLLO ........................................................................................... 6
Configurar el entorno de desarrollo .................................................................................... 6
CREAR UNA APP ............................................................................................................... 11
Ejecutar la App en un emulador........................................................................................ 11
Ejecutar la App en un dispositivo físico ........................................................................... 12
COMPONENTES CENTRALES ........................................................................................ 13
Crear una ventana de inicio .............................................................................................. 13
Imagen de Fondo ........................................................................................................... 13
Formulario de ingreso ................................................................................................... 14
Elementos del formulario .............................................................................................. 17
Crear elementos personalizados .................................................................................... 20
Pasando parámetros al componente .............................................................................. 22
Crear estilos globales .................................................................................................... 23
NAVEGACION ENTRE PANTALLAS ............................................................................. 25
Separando las pantallas ..................................................................................................... 25
Crear pantalla de registro .................................................................................................. 30
Agregar componentes a la pantalla de registro ................................................................. 32
Capturar valores de los inputs ........................................................................................... 36
ORGANIZANDO EL CÓDIGO CON EL PATRÓN DE DISEÑO MVVM ...................... 38
Reorganizar las carpetas según las convenciones de Google ........................................... 38
Capa de Presentación .................................................................................................... 38
Capa de Dominio ........................................................................................................... 38
Capa de Datos................................................................................................................ 38
Crear un componente personalizado para los inputs ........................................................ 40
Separar las hojas de estilos ............................................................................................... 47
MONTANDO UN SERVIDOR NODE JS .......................................................................... 52
Prueba de Rutas del servidor............................................................................................. 53
CONECTANDO A LA BASE DE DATOS (MySQL) ........................................................ 56
Realizando la conexión desde Node.js ............................................................................. 56
Creando un usuario ........................................................................................................... 60
Creando usuarios desde la App ......................................................................................... 60
AJUSTANDO EL PROYECTO A LA ARQUITECTURA MVVM .................................. 62
Ajustar el dominio ............................................................................................................ 62
Ajustes a las pantallas para mejorar la presentación ......................................................... 65
Ajustar la interfase ............................................................................................................ 66
Estructura de carpetas del proyecto .................................................................................. 68
Organización de los módulos de código ........................................................................... 70
Validaciones en los formularios ....................................................................................... 71
Cambios al tipo de respuesta y validaciones ................................................................. 72
Encriptar el password .................................................................................................... 77
JSON WEB TOKEN ............................................................................................................ 80
Configuración del back-end para generar el token ........................................................... 80
Enviando el login desde la App ........................................................................................ 87
Almacenamiento interno la de sesión del usuario............................................................. 93
CUSTOM HOOKS ............................................................................................................... 98
Implementación del Custom Hook ................................................................................... 98
Navegar usando el Custom hook .................................................................................... 100
Cerrar la sesión ............................................................................................................... 105
DESARROLLO DE APPS
La creación de una aplicación (APP) se refiere al proceso de desarrollar software para
dispositivos móviles o de escritorio que brinda funcionalidades específicas a los usuarios.
Existen dos enfoques principales para desarrollar aplicaciones móviles: plataformas nativas
y plataformas multiplataforma.

Las plataformas nativas, como Android o iOS, permiten desarrollar aplicaciones utilizando
los lenguajes de programación y las herramientas específicas de cada plataforma. Esto
significa que se debe escribir código separado para cada plataforma, lo que puede requerir
más tiempo y recursos.

Por otro lado, los sistemas multiplataforma, como React Native y Flutter, permiten
desarrollar aplicaciones utilizando un único código base que se puede ejecutar en múltiples
plataformas. Estas plataformas utilizan frameworks y bibliotecas que traducen el código a
un lenguaje nativo para cada plataforma.

Además de las funcionalidades proporcionadas por las plataformas nativas, las aplicaciones
móviles a menudo hacen uso de bibliotecas de terceros para agregar características
adicionales. Estas bibliotecas pueden incluir funcionalidades como la integración con
servicios en la nube, análisis de datos, autenticación de usuarios, entre otros.

En resumen, al crear una aplicación, se debe considerar si se utilizará una plataforma nativa
o una plataforma multiplataforma, si se requerirá almacenamiento de datos local utilizando
SQLite1 y si se utilizarán bibliotecas de terceros para agregar funcionalidades adicionales.
A continuación, se presenta una tabla comparativa de las herramientas más utilizadas para
proyectos móviles (tomado de
https://rua.ua.es/dspace/bitstream/10045/136523/1/Estudio_y_benchmarking_de_tecnologi
as_de_creacion_de_Gonzalez_Torres_Ricardo.pdf)

Tecnología Año Plataforma Tipo Lenguaje Interfaz % de


salida Gráfica uso a
2023
XCode 2003 iOS Nativo Swift Si 3
Android 2014 Android Nativo JAVA/Kotlin Si 31 java/
Studio 8 Kotlin
Flutter 2017 Multi Híbrido Dart No 3
React 2015 Multi Híbrido JavaScript No 33
Native
Ionic 2013 Multi Híbrido TypeScript No 18
Xamarin 2011 Multi Híbrido C# No 14

1
SQLite es una biblioteca de base de datos relacional que se utiliza comúnmente en
aplicaciones móviles para almacenar y administrar datos localmente en el dispositivo del
usuario. Proporciona una forma eficiente y confiable de almacenar datos estructurados.
REACT NATIVE
React Native es una opción popular para el desarrollo de aplicaciones móviles debido a
varias razones:

Eficiencia de desarrollo: React Native permite escribir código una vez y ejecutarlo en
múltiples plataformas, como iOS y Android. Esto reduce el tiempo y los recursos
necesarios para desarrollar y mantener aplicaciones móviles.

Rendimiento nativo: A diferencia de las aplicaciones híbridas, las aplicaciones


desarrolladas con React Native se ejecutan directamente en el dispositivo, lo que
proporciona un rendimiento similar al de las aplicaciones nativas.

Reutilización de código: React Native permite reutilizar componentes de interfaz de


usuario entre diferentes plataformas, lo que facilita el desarrollo y la actualización de
aplicaciones para múltiples sistemas operativos.

Comunidad activa: React Native cuenta con una gran comunidad de desarrolladores que
comparten conocimientos, recursos y bibliotecas de código abierto. Esto facilita el
aprendizaje y la resolución de problemas durante el desarrollo de aplicaciones.

Integración con tecnologías existentes: React Native se puede integrar fácilmente con
código nativo existente, lo que permite aprovechar las funcionalidades y características
específicas de cada plataforma.

Menor curva de aprendizaje: para aquellos desarrolladores Front-End, la curva de


aprendizaje es más rápida, dado su previo conocimiento de JavaScript, HTML y CSS.

En resumen, utilizar React Native puede acelerar el desarrollo de aplicaciones móviles,


ofrecer un rendimiento nativo y permitir la reutilización de código entre diferentes
plataformas.
ENTORNO DE DESARROLLO
En este apartado se muestran los recursos necesarios para el desarrollo con React Native y
su instalación, comprende el editor y sus dependencias necesarias, node.js como servidor,
un emulador y el conversor de código para iOS y Android.

Configurar el entorno de desarrollo


1. Instalar Visual Studio Code (VSC). En el asistente de instalación dejar marcada la
opción “Agregar PATH…”
2. Ejecutar VSC e instalar dependencias, en la opción “Extensiones”:
a. “ES7 React/Redux/React-Native snippets”, suministra funciones nativas de
React y Redux
b. “Simple React Snippets”, es un conjunto de ayudas
c. “Auto Close Tag”, ayuda para la creación de etiquetas (tags)
d. “Paste JSON as Code” para manipular JSON, es posible que ya esté
instalado.
e. “TypeScript importer”

3. Instalar Android Studio. Desde la página oficial de Android Studio


“developer.android.com/studio”.
a. Dejar habilitado “Android Virtual Device”
4. Instalar Node.js, de “node.org/es/download/”. Descargar la última versión. Dejar las
opciones por defecto. En consola ejecutar “node --version” para verificar.
5. Instalar Postman (postman.com/downloads/), para realizar peticiones HTTP
6. Crear un emulador

a. Ejecutar Android Studio


b. La opción “Virtual Device Manager”
c. “Create Device”, seleccionarf “Phone” y buscar un emulador que tenga los
servicios de Google Service para probar las aplicaciones sin restricciones
(icono de Play Store)

d. Botón “Next” y descargar una versión, en este caso “Tiramisu”, descargar la


API correspondiente:

e. Puede dejar las opciones por defecto y botón “Finish”


f. Para ejecutar el emulador en la punta de flecha de la columna “Actions”, la
primera vez demorará más tiempo.

g. En la parte superior del emulador, deslizar para visualizar las notificaciones,


esperar hasta que termine la configuración.
h. Clic en el área azul, lleva a la siguiente pantalla

:
i. Mas adelante, ingresar en el emulador, su correo Gmail

7. Instalar Expo CLI, Una interfaz de línea de comandos que permite montar un
servidor para correr el proyecto en localmente, construir proyectos sencillos y
publicarlo. En Google buscar “expo install” y el enlace “Como instalar Expo (React
Native) – gists – GitHub”
a. Copiar el comando “npm install -g expo-cli exp” y ejecutarlo en Power
Shell, como administrador.

b. Verificar con “expo --version”.


c. Si hay problemas con versiones desactualizadas, ejecutar:
i. npm uninstall -g expo-cli
ii. npm install –save-dev @expo-cli
iii. Si ya tiene un proyecto, reemplace en el archivo “package.json”:
“scripts”:{ “start”: “expo start”} por “scripts”:{ “start”: “npx
expo start”}
CREAR UNA APP
1. Prepara una carpeta para el desarrollo del proyecto ejecutar VSC, abrir una consola
y verificar que la ruta corresponda a esa carpeta.

2. En Google, buscar “react native install typescript” (ir a


https://reactnative.dev/docs/typescript), para obtener los comandos a ejecutar.

3. En la consola de VSC, ejecutar el comando “npx create-expo-app --template” (se


sugiere escribir el comando, no copiarlo)
a. Seleccionar con tab la opción “Blank (TypeScript)
b. Darle un nombre a la aplicación y enter.
c. Se creará la carpeta del proyecto

i. En la carpeta “assets” se tienen los recursos del sistema (imágenes,


etc.)
ii. “App.tst” es el archivo inicial de la aplicación
iii. En “package.json” se tienen las dependencias a utilizar en el
desarrollo del proyecto.

Ejecutar la App en un emulador

1. En la terminal de VSC
a. Cambiar a la carpeta de proyecto: “cd AppReactNAtive“
b. ejecutar “npm run Android” , se lanzara el emulador.

c. ¡En el archivo “App.tsx” cambiar el mensaje dentro de la etiqueta <Text> a


“HOLA MUNDO!” y guardar (Ctl-S), inmediatamente cambiara el texto en
el emulador.

Ejecutar la App en un dispositivo físico

1. En el dispositivo, ir a tienda, para Android es Play Store, buscar “expo go” e


instalarla.
2. En la terminal de VSC, ejecutar “expo start”. Si le solicita dependencias
adicionales, pulsar “Y” para instalarlas. Se generará un código QR.
3. Abrir la aplicación Expo Go en el dispositivo.
4. escanear el código QR con el dispositivo. Los dos equipos deben estar en la misma
red WiFi.
COMPONENTES CENTRALES
El módulo principal, que se ejecuta al lanzar la aplicación es “App”, dentro de él se
encuentran las “Views” que son las diferentes pantallas donde se realiza la navegación.
Dentro de los Views hay componentes. Los views se relacionan con “styles”, que son los
estilos aplicados a cada vista.

Crear una ventana de inicio

Buscar en Google “React native components”, en “Core Components” para tener una guía
al construir el código.

Imagen de Fondo

Copie los archivos de imágenes suministrados, en la carpeta “assets”


Modifique el código del archivo App.tsx como se muestra:
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View, Image } from 'react-native';

export default function App() {


return (
<View style={styles.container}>
<Image
source={ require('./assets/chef.jpg')}
style={styles.imageBackground}
/>
</View>
);
}

const styles = StyleSheet.create({


container: {
flex: 1,
backgroundColor: '#fff',
},
imageBackground: {
width: '100%',
height: '100%',
},
});

Guarde los cambios y la aplicación cambiará así:

Formulario de ingreso

Agregue una vista interna, con sus estilos. Modifique el código así:

import { StatusBar } from 'expo-status-bar';


import { StyleSheet, Text, View, Image } from 'react-native';

export default function App() {


return (
<View style={styles.container}>
<Image
source={require('./assets/chef.jpg')}
style={styles.imageBackground}
/>
<View style={styles.form}>
</View>

</View>
);
}

const styles = StyleSheet.create({


container: {
flex: 1,
backgroundColor: 'black',
},
imageBackground: {
width: '100%',
height: '100%',
opacity: 0.7,
bottom: '30%',
},
form:{
width: '100%',
height: '40%',
backgroundColor: 'white',
position: 'absolute',
bottom: 0,
borderTopLeftRadius: 40,
borderTopRightRadius: 40,
}
});

La App contendrá la caja del formulario:


Inserte la siguiente View justo después de la imagen de fondo:

<View style={styles.logoContainer}>
<Image
source={require('./assets/logo.png')}
style={styles.logoImage}
/>
<Text style={styles.logoText}>FOOD APP</Text>
</View>

Y los siguientes estilos:

logoContainer:{
position: 'absolute',
alignSelf: 'center',
top: '15%',
},
logoImage: {
width: 100,
height: 100,
},
logoText: {
color: 'white',
textAlign: 'center',
fontSize: 20,
marginTop: 10,
fontWeight: 'bold',
}

Se obtendrá la siguiente pantalla:

Elementos del formulario

Modificar el archivo “App.tsx”, así:

import { StatusBar } from 'expo-status-bar';


import { StyleSheet, Text, View, Image, TextInput, Button, ToastAndroid }
from 'react-native';

export default function App() {


return (
<View style={styles.container}>
<Image
source={require('./assets/chef.jpg')}
style={styles.imageBackground}
/>
<View style={styles.logoContainer}>
<Image
source={require('./assets/logo.png')}
style={styles.logoImage}
/>
<Text style={styles.logoText}>FOOD APP</Text>
</View>

<View style={styles.form}>
<Text style={styles.formText}>INGRESAR</Text>
<View style={styles.formInput}>
<Image style={styles.formIcon}
source={require('./assets/email.png')}
/>
<TextInput
style={styles.formTextInput}
placeholder='Correo electrónico'
keyboardType='email-address'
/>
</View>
<View style={styles.formInput}>
<Image style={styles.formIcon}
source={require('./assets/password.png')}
/>
<TextInput
style={styles.formTextInput}
placeholder='Contraseña'
keyboardType='default'
secureTextEntry={true}
/>
</View>

<View style={{ marginTop: 30 }}>


<Button
title='ENTRAR'
onPress={() => ToastAndroid.show('CLICK', ToastAndroid.LONG)}
color={'orange'}
/>
</View>

<View style={styles.formRegister}>
<Text>¿No tienes cuenta?</Text>
<Text style={styles.formRegisterText}>Regístrate</Text>
</View>

</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'black',
},
imageBackground: {
width: '100%',
height: '100%',
opacity: 0.7,
bottom: '30%',
},
form: {
width: '100%',
height: '40%',
backgroundColor: 'white',
position: 'absolute',
bottom: 0,
borderTopLeftRadius: 40,
borderTopRightRadius: 40,
padding: 30,
},
formText: {
fontWeight: 'bold',
fontSize: 16,
},
formIcon: {
width: 25,
height: 25,
marginTop: 5,

},
formInput: {
flexDirection: 'row',
marginTop: 30,

},

formTextInput: {
flex: 1,
borderBottomWidth: 1,
borderBottomColor: '#AAAAAA',
marginLeft: 15,
},
formRegister: {
flexDirection: 'row',
justifyContent: 'center',
marginTop: 30,
},

formRegisterText: {
fontStyle: 'italic',
color: 'orange',
borderBottomWidth: 1,
borderBottomColor: 'orange',
fontWeight: 'bold',
marginLeft: 10,
},
logoContainer: {
position: 'absolute',
alignSelf: 'center',
top: '15%',
},
logoImage: {
width: 100,
height: 100,
},
logoText: {
color: 'white',
textAlign: 'center',
fontSize: 20,
marginTop: 10,
fontWeight: 'bold',
},
});

Crear elementos personalizados

Crear una carpeta “src” dentro de la carpeta principal


Dentro de “src” crear dos carpetas “components” y “views”
Dentro de “components” crear un archivo “RoundedButton.tsx”
En el archivo digitar “racfc” y aceptar el snippet:

import React from 'react'

export const RoundedButton = () => {


return (
<div>RoundedButton</div>
)
}

Eliminar la línea con la etiqueta <div> y modificar:

import React from 'react'


import { TouchableOpacity, Text } from 'react-native'

export const RoundedButton = () => {


return (
<TouchableOpacity
onPress={() => {}}

>
<Text>ENTRAR</Text>
</TouchableOpacity>
)
}

En el archivo “App.tsx”, eliminar la etiqueta Button y cambiar por el elemento


personalizado:

<View style={{ marginTop: 30 }}>


<RoundedButton />

</View>

Observe que se debe crear la línea del import:

import { RoundedButton } from './src/components/RoundedButton';

Si no, insertarla manualmente en la sección de imports.


Modificar “RoundedButton.tsx” así:

import React from 'react'


import { TouchableOpacity, Text, StyleSheet } from 'react-native'

export const RoundedButton = () => {


return (
<TouchableOpacity
style={styles.RoundedButton}
onPress={() => { }}

>
<Text style={styles.textButton} >ENTRAR</Text>
</TouchableOpacity>
)
}

const styles = StyleSheet.create({


RoundedButton: {
width: '100%',
height: 50,
backgroundColor: 'orange',
alignItems: 'center',
justifyContent: 'center',
borderRadius: 15,
},
textButton: {
color: 'white',
}
});

Pasando parámetros al componente

Se crea una interfase, por convención se llama “Props”, en “RoundedButton.tsx”, después


de los imports:

interface Props {
text: string;
onPress: () => void,

Modificar el elemento RoundedButton:

export const RoundedButton = ({ text, onPress}: Props) => {


return (
<TouchableOpacity
style={styles.RoundedButton}
onPress={() => onPress()}
>
<Text style={styles.textButton} >{ text}</Text>
</TouchableOpacity>
)
}
En el archivo “App.tsx” para pasar los parámetros, modificar la etiqueta <RoundedButton>
así:

<View style={{ marginTop: 30 }}>


<RoundedButton text='ENTRAR' onPress={ () => ToastAndroid.show('HOLA!',
ToastAndroid.SHORT)}/>
</View>

Verifique el funcionamiento del código anterior, ¡debe aparecer una pequeña ventana
emergente con el mensaje “HOLA!”

Crear estilos globales

Dentro de la carpeta “src” crear una carpeta “theme” y dentro de esta el archivo
“AppTheme.tsx”

En “AppTheme.tsx” el siguiente código:

import { StyleSheet } from "react-native";

export const MyColors = {


background: '#EEEEEE',
primary: '#F4991A',
secondary: '# E14D2A',

En “RoundedButton.tsx”, cambiar el color de fondo:


backgroundColor: MyColors.primary,

Se debe generar el import:

import { MyColors } from '../theme/AppTheme';


NAVEGACION ENTRE PANTALLAS
Detener el servidor (crl+c).
Instalar manualmente. Consultar en “reactnative.dev/docs/navigation” y ejecutar en la
terminal el comando:

npm install @react-navigation/native @react-navigation/native-stack

Después, instalar las dependencias con “expo”:

npx expo install react-native-screens react-native-safe-area-context

Separando las pantallas

En la carpeta “views” crear otra carpeta “home” y en ella el archivo “home.tsx”:

En este archivo teclear “rafc” para generar el snippet, cambiar por HomeScreen:

import React from 'react'

export const HomeScreen = () => {


return (
<div>Screen</div>
)
}

Cortar todo el código, desde el return con la pantalla inicial, desde “App.tsx” en
“home.tsx”, quedará así:

import React from 'react'


import { View, Text, StyleSheet, Image, TextInput, ToastAndroid } from
'react-native'
import { RoundedButton } from '../../components/RoundedButton';

export const HomeScreen = () => {

return (
<View style={styles.container}>
<Image
source={require('./assets/chef.jpg')}
style={styles.imageBackground}
/>
<View style={styles.logoContainer}>
<Image
source={require('./assets/logo.png')}
style={styles.logoImage}
/>
<Text style={styles.logoText}>FOOD APP</Text>
</View>

<View style={styles.form}>
<Text style={styles.formText}>INGRESAR</Text>
<View style={styles.formInput}>
<Image style={styles.formIcon}
source={require('./assets/email.png')}
/>
<TextInput
style={styles.formTextInput}
placeholder='Correo electrónico'
keyboardType='email-address'
/>
</View>
<View style={styles.formInput}>
<Image style={styles.formIcon}
source={require('./assets/password.png')}
/>
<TextInput
style={styles.formTextInput}
placeholder='Contraseña'
keyboardType='default'
secureTextEntry={true}
/>
</View>

<View style={{ marginTop: 30 }}>


<RoundedButton text='ENTRAR' onPress={() =>
ToastAndroid.show('HOLA!', ToastAndroid.SHORT)} />
</View>

<View style={styles.formRegister}>
<Text>¿No tienes cuenta?</Text>
<Text style={styles.formRegisterText}>Regístrate</Text>
</View>

</View>
</View>
);
}

const styles = StyleSheet.create({


container: {
flex: 1,
backgroundColor: 'black',
},
imageBackground: {
width: '100%',
height: '100%',
opacity: 0.7,
bottom: '30%',
},
form: {
width: '100%',
height: '40%',
backgroundColor: 'white',
position: 'absolute',
bottom: 0,
borderTopLeftRadius: 40,
borderTopRightRadius: 40,
padding: 30,
},
formText: {
fontWeight: 'bold',
fontSize: 16,
},
formIcon: {
width: 25,
height: 25,
marginTop: 5,

},
formInput: {
flexDirection: 'row',
marginTop: 30,

},
formTextInput: {
flex: 1,
borderBottomWidth: 1,
borderBottomColor: '#AAAAAA',
marginLeft: 15,
},
formRegister: {
flexDirection: 'row',
justifyContent: 'center',
marginTop: 30,
},

formRegisterText: {
fontStyle: 'italic',
color: 'orange',
borderBottomWidth: 1,
borderBottomColor: 'orange',
fontWeight: 'bold',
marginLeft: 10,
},
logoContainer: {
position: 'absolute',
alignSelf: 'center',
top: '15%',
},
logoImage: {
width: 100,
height: 100,
},
logoText: {
color: 'white',
textAlign: 'center',
fontSize: 20,
marginTop: 10,
fontWeight: 'bold',
},
});

Desde la página de Real Native, copiar el código en el apartado “Usage”:


Y reemplazar el archivo “App.tsx”. Cambiar algunos nombres para que el código quede así:

import * as React from 'react';


import {NavigationContainer} from '@react-navigation/native';
import {createNativeStackNavigator} from '@react-navigation/native-stack';
import { HomeScreen } from './src/views/home/home';

const Stack = createNativeStackNavigator();

const App = () => {


return (
<NavigationContainer>
<Stack.Navigator screenOptions={{
headerShown: false
}}>

<Stack.Screen
name="HomeScreen"
component={HomeScreen}

/>
{ /*<Stack.Screen name="Profile" component={ProfileScreen} /> */}
</Stack.Navigator>
</NavigationContainer>
);
};
export default App;

Al compilar y ejecutar expo, se genera un error debido a las rutas de las imágenes, cambiar
así:

<Image
source={require('../../../assets/chef.jpg')}
style={styles.imageBackground}
/>
<View style={styles.logoContainer}>
<Image
source={require('../../../assets/logo.png')}
style={styles.logoImage}
/>

Y lo mismo para los demás recursos.

Crear pantalla de registro

Dentro de la carpeta “View” crear una carpeta “register” y en ella un archivo


“Register.tsx”:

import React from 'react'


import { View, Text } from 'react-native'

export const RegisterScreen = () => {


return (
<View style={{flex:1, justifyContent: 'center', alignItems: 'center'}}>
<Text>RegisterScreen</Text>
</View>
)
}

En “App.tsx” agregar la otra pantalla:

import * as React from 'react';


import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { HomeScreen } from './src/views/home/home';
import { RegisterScreen } from './src/views/register/Register';

export type RootStackParamList = {


HomeScreen: undefined;
RegisterScreen: undefined;
};

const Stack = createNativeStackNavigator <RootStackParamList>


();

const App = () => {


return (
<NavigationContainer>
<Stack.Navigator screenOptions={{
headerShown: false
}}>
<Stack.Screen
name="HomeScreen"
component={HomeScreen}
/>
<Stack.Screen
name="RegisterScreen"
component={RegisterScreen}
options={{
headerShown: true,
title: 'Registro',
}}
/>

</Stack.Navigator>
</NavigationContainer>
);
};

export default App;

En “home.tsx” agregar el import y la constante navigation:

import { StackNavigationProp } from '@react-navigation/stack';


import { RootStackParamList } from '../../../App';

export const HomeScreen = () => {

const navigation =
useNavigation<StackNavigationProp<RootStackParamList>>();

return (
Debe ejecutar en la terminal el siguiente comando para instalar el complemento “npm i
@react-navigation/stack”. Debe verse registrado en el archivo “package.json”.

Agregar componentes a la pantalla de registro

Reutilizar el código de la pantalla de home (“home.tsx”) en “Register.tsx” haciendo los


cambios necesarios en los componentes y los estilos:

import React from 'react'


import { useNavigation } from '@react-navigation/native';
import { View, Text, StyleSheet, Image, TextInput, ToastAndroid, Touchable,
TouchableOpacity } from 'react-native';
import { RoundedButton } from '../../components/RoundedButton';
import { StackNavigationProp } from '@react-navigation/stack';
import { RootStackParamList } from '../../../App';
export const RegisterScreen = () => {

return (
<View style={styles.container}>
<Image
source={require('../../../assets/chef.jpg')}
style={styles.imageBackground}
/>
<View style={styles.logoContainer}>
<Image
source={require('../../../assets/user_image.png')}
style={styles.logoImage}
/>
<Text style={styles.logoText}>SELECCIONA UNA IMAGEN</Text>
</View>

<View style={styles.form}>
<Text style={styles.formText}>REGISTRARSE</Text>

<View style={styles.formInput}>
<Image style={styles.formIcon}
source={require('../../../assets/user.png')}
/>
<TextInput
style={styles.formTextInput}
placeholder='Nombres'
keyboardType='default'
/>
</View>
<View style={styles.formInput}>
<Image style={styles.formIcon}
source={require('../../../assets/my_user.png')}
/>
<TextInput
style={styles.formTextInput}
placeholder='Apellidos'
keyboardType='default'
/>
</View>

<View style={styles.formInput}>
<Image style={styles.formIcon}
source={require('../../../assets/email.png')}
/>
<TextInput
style={styles.formTextInput}
placeholder='Correo electrónico'
keyboardType='email-address'
/>
</View>

<View style={styles.formInput}>
<Image style={styles.formIcon}
source={require('../../../assets/phone.png')}
/>
<TextInput
style={styles.formTextInput}
placeholder='Teléfono'
keyboardType='numeric'
/>
</View>

<View style={styles.formInput}>
<Image style={styles.formIcon}
source={require('../../../assets/password.png')}
/>
<TextInput
style={styles.formTextInput}
placeholder='Contraseña'
keyboardType='default'
secureTextEntry={true}
/>
</View>
<View style={styles.formInput}>
<Image style={styles.formIcon}
source={require('../../../assets/confirm_password.png')}
/>
<TextInput
style={styles.formTextInput}
placeholder='Confirmar Contraseña'
keyboardType='default'
secureTextEntry={true}
/>
</View>
<View style={{ marginTop: 30 }}>
<RoundedButton text='CONFIRMAR' onPress={() =>
ToastAndroid.show('HOLA!', ToastAndroid.SHORT)} />
</View>

</View>
</View>
);
}

const styles = StyleSheet.create({


container: {
flex: 1,
backgroundColor: 'black',
},

imageBackground: {
width: '100%',
height: '100%',
opacity: 0.7,
bottom: '30%',
},

form: {
width: '100%',
height: '70%',
backgroundColor: 'white',
position: 'absolute',
bottom: 0,
borderTopLeftRadius: 40,
borderTopRightRadius: 40,
padding: 30,
},
formText: {
fontWeight: 'bold',
fontSize: 16,
},

formIcon: {
width: 25,
height: 25,
marginTop: 5,
},

formInput: {
flexDirection: 'row',
marginTop: 25,
},

formTextInput: {
flex: 1,
borderBottomWidth: 1,
borderBottomColor: '#AAAAAA',
marginLeft: 15,
},

formRegister: {
flexDirection: 'row',
justifyContent: 'center',
marginTop: 30,
},

formRegisterText: {
fontStyle: 'italic',
color: 'orange',
borderBottomWidth: 1,
borderBottomColor: 'orange',
fontWeight: 'bold',
marginLeft: 10,
},
logoContainer: {
position: 'absolute',
alignSelf: 'center',
top: '5%',
alignItems: 'center',
},
logoImage: {
width: 100,
height: 100,
},
logoText: {
color: 'white',
textAlign: 'center',
fontSize: 20,
marginTop: 10,
fontWeight: 'bold',
},
});

Obtendrá una pantalla como la siguiente:

Capturar valores de los inputs

Importar useState en “home.tsx”:

import React, { useState} from 'react';

Agregar constantes para cada campo del formulario, antes de la constante navigation:
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const navigation =
useNavigation<StackNavigationProp<RootStackParamList>>();

Relacionar las constantes con los inputs del formulario y controlar el evento:

<TextInput
style={styles.formTextInput}
placeholder='Correo electrónico'
keyboardType='email-address'
value={email}
onChangeText={ text => setEmail(text)}
/>

<TextInput
style={styles.formTextInput}
placeholder='Contraseña'
keyboardType='default'
secureTextEntry={true}
value={password}
onChangeText={ text => setPassword(text)}
/>

Para probar, cambiar el evento del botón para enviar los valores a la terminal:

<View style={{ marginTop: 30 }}>


<RoundedButton text='ENTRAR' onPress={() =>{
console.log('Email: ' + email);
console.log('Password: ' + password);
}} />
</View>

SI todo va bien, en la terminal se mostrarán los valores digitados, al dar clic en el botón:
ORGANIZANDO EL CÓDIGO CON EL PATRÓN DE DISEÑO MVVM

Reorganizar las carpetas según las convenciones de Google

Capa de Presentación
Contendrá todo lo relacionado con las vistas.
 Crear una carpeta “Presentation” dentro de “src”.
 Arrastrar a ella las carpetas “components”, “theme” y “views”, debe detener la
aplicación y cerrar VSC para que permita el cambio manual.
 Se deben cambiar las rutas de los recursos, agregando “../”, en “App.tsx” a

 import { HomeScreen } from './src/Presentation/views/home/home';
 import { RegisterScreen } from
'./src/Presentation/views/register/Register';

Capa de Dominio
 Dentro de “src” cree una carpeta “Domain”.
Capa de Datos
 Dentro de “src” cree una carpeta “Data”.
Pasar los userState a cada una de las carpetas, creando un archivo ‘viewModel.tsx’ en cada
carpeta de ‘views’, cortar los userState de “Home.tsx” y en ‘viewModel.tsx’ construir un
objeto así:

import React, {useState} from 'react'

const HomeViewModel = () => {


const [values, setValues] = useState({
email:'',
password:'',
});

const onChange = (property: string, value: any) => {


setValues({...values, [property]: value});
}

return {
...values,
onChange
}
}

export default HomeViewModel;

Nota: los tres puntos en el código realizan una “desestructuración”, es decir, separa los
elementos de la estructura original.

En “Home.tsx” modificar:

import useViewModel from './ViewModel';

export const HomeScreen = () => {


const {email, password, onChange
} = useViewModel();
const navigation = useNavigation<StackNavigationProp<RootStackParamList>>();

return (

En los bloques <TextInput> de “Home.tsx”, cambiar:

<TextInput
style={styles.formTextInput}
placeholder='Contraseña'
keyboardType='default'
secureTextEntry={true}
value={password}
onChangeText={ text => onChange('email', text)}
/>

<TextInput
style={styles.formTextInput}
placeholder='Contraseña'
keyboardType='default'
secureTextEntry={true}
value={password}
onChangeText={ text => onChange('password', text)}
/>

Hay que confirmar que todo esté correcto, ingresando los datos y dando clic en el botón. El
código funciona lo mismo que anteriormente, pero está organizado de una manera más
profesional.

Crear un componente personalizado para los inputs

En la carpeta “components” crear un archivo “CusatomTextInput.tsx”, y en él generar


código con ‘racf’, modificar así:

import React from 'react'


import { View, Image, TextInput, StyleSheet, KeyboardType } from 'react-
native';

interface Props {
image: any;
placeholder: string;
value: string;
keyboardType: KeyboardType,
secureTextEntry?: boolean,
property: string,
onChangeText: (property: string, value: any) => void,
}

export const CustomTextInput = ({


image,
placeholder,
value,
keyboardType,
secureTextEntry = false,
property,
onChangeText
}: Props) => {
return (
<View style={styles.formInput}>
<Image style={styles.formIcon}
source={image}
/>
<TextInput
style={styles.formTextInput}
placeholder={placeholder}
keyboardType={keyboardType}
value={value}
onChangeText={text => onChangeText(property, text)}
secureTextEntry={secureTextEntry}
/>
</View>
)
}

const styles = StyleSheet.create({


formIcon: {
width: 25,
height: 25,
marginTop: 5,

},
formInput: {
flexDirection: 'row',
marginTop: 30,

},
formTextInput: {
flex: 1,
borderBottomWidth: 1,
borderBottomColor: '#AAAAAA',
marginLeft: 15,
}
})

Modificar el archivo “home.tsx”:

import React, { useState} from 'react';


import { useNavigation } from '@react-navigation/native';
import { View, Text, StyleSheet, Image, TextInput, ToastAndroid, Touchable,
TouchableOpacity } from 'react-native';
import { RoundedButton } from
'../../../Presentation/components/RoundedButton';
import { StackNavigationProp } from '@react-navigation/stack';
import { RootStackParamList } from '../../../../App';
import useViewModel from './ViewModel';
import { CustomTextInput } from '../../components/CustomTextInput';

export const HomeScreen = () => {


const {email, password, onChange} = useViewModel();
const navigation =
useNavigation<StackNavigationProp<RootStackParamList>>();

return (
<View style={styles.container}>
<Image
source={require('../../../../assets/chef.jpg')}
style={styles.imageBackground}
/>
<View style={styles.logoContainer}>
<Image
source={require('../../../../assets/logo.png')}
style={styles.logoImage}
/>
<Text style={styles.logoText}>FOOD APP</Text>
</View>

<View style={styles.form}>
<Text style={styles.formText}>INGRESAR</Text>

<CustomTextInput
image= {require('../../../../assets/email.png')}
placeholder='Correo electrónico'
keyboardType='email-address'
property='email'
onChangeText={onChange}
value={email}
/>
<CustomTextInput
image= {require('../../../../assets/password.png')}
placeholder='Contraseña'
keyboardType='default'
property='password'
onChangeText={onChange}
value={password}
secureTextEntry={true}

/>

<View style={{ marginTop: 30 }}>


<RoundedButton text='ENTRAR' onPress={() =>{
console.log('Email: ' + email);
console.log('Password: ' + password);
}} />
</View>

<View style={styles.formRegister}>
<Text>¿No tienes cuenta?</Text>
<TouchableOpacity onPress={() =>
navigation.navigate('RegisterScreen')}>
<Text
style={styles.formRegisterText}>Regístrate</Text>
</TouchableOpacity>
</View>

</View>
</View>
);
}

const styles = StyleSheet.create({


container: {
flex: 1,
backgroundColor: 'black',
},
imageBackground: {
width: '100%',
height: '100%',
opacity: 0.7,
bottom: '30%',
},
form: {
width: '100%',
height: '40%',
backgroundColor: 'white',
position: 'absolute',
bottom: 0,
borderTopLeftRadius: 40,
borderTopRightRadius: 40,
padding: 30,
},
formText: {
fontWeight: 'bold',
fontSize: 16,
},
formRegister: {
flexDirection: 'row',
justifyContent: 'center',
marginTop: 30,
},

formRegisterText: {
fontStyle: 'italic',
color: 'orange',
borderBottomWidth: 1,
borderBottomColor: 'orange',
fontWeight: 'bold',
marginLeft: 10,
},
logoContainer: {
position: 'absolute',
alignSelf: 'center',
top: '15%',
},
logoImage: {
width: 100,
height: 100,
},
logoText: {
color: 'white',
textAlign: 'center',
fontSize: 20,
marginTop: 10,
fontWeight: 'bold',
},
});

Ahora se están usando componentes personalizados.


Crear un archivo “ViewModel.tsx” en la carpeta “register”. Se recomienda cerrar otros
archivos para evitar confusiones debido a sus similitudes.

El archivo quedará así:

import React, { useState } from 'react'

const RegisterViewModel = () => {


const [values, setValues] = useState({
name: '',
lastname: '',
phone: '',
email: '',
password: '',
confirmPassword: '',
});

const onChange = (property: string, value: any) => {


setValues({ ...values, [property]: value });
}

const register = () => {


console.log(JSON.stringify(values));
}

return {
...values,
onChange,
register
}
}

export default RegisterViewModel;

Observe que se modifica el evento para mostrar en la terminal los valores ingresados.
Modificar el archivo “register.tsx” así:

import React from 'react'


import { View, Text, StyleSheet, Image, TextInput, ToastAndroid, Touchable,
TouchableOpacity } from 'react-native';
import { RoundedButton } from
'../../../Presentation/components/RoundedButton';
import useViewModel from './ViewModel';
import { CustomTextInput } from
'../../../Presentation/components/CustomTextInput';

export const RegisterScreen = () => {


const { name, lastname, phone, email, password, confirmPassword, onChange,
register } = useViewModel();

return (
<View style={styles.container}>
<Image
source={require('../../../../assets/chef.jpg')}
style={styles.imageBackground}
/>
<View style={styles.logoContainer}>
<Image
source={require('../../../../assets/user_image.png')}
style={styles.logoImage}
/>
<Text style={styles.logoText}>SELECCIONA UNA IMAGEN</Text>
</View>

<View style={styles.form}>
<Text style={styles.formText}>REGISTRARSE</Text>

<CustomTextInput
image={require('../../../../assets/user.png')}
placeholder='Nombres'
keyboardType='default'
property='name'
onChangeText={onChange}
value={name}
/>

<CustomTextInput
image={require('../../../../assets/my_user.png')}
placeholder='Apellidos'
keyboardType='default'
property='lastname'
onChangeText={onChange}
value={lastname}
/>

<CustomTextInput
image={require('../../../../assets/email.png')}
placeholder='Correo electrónico'
keyboardType='email-address'
property='email'
onChangeText={onChange}
value={email}
/>

<CustomTextInput
image={require('../../../../assets/phone.png')}
placeholder='Teléfono'
keyboardType='numeric'
property='phone'
onChangeText={onChange}
value={phone}
/>
<CustomTextInput
image={require('../../../../assets/password.png')}
placeholder='Contraseña'
keyboardType='default'
property='password'
onChangeText={onChange}
value={password}
secureTextEntry={true}
/>

<CustomTextInput
image={require('../../../../assets/confirm_password.png')}
placeholder='Confirmar Contraseña'
keyboardType='default'
property='confirmPassword'
onChangeText={onChange}
value={confirmPassword}
secureTextEntry={true}
/>

<View style={{ marginTop: 30 }}>


<RoundedButton text='CONFIRMAR' onPress={() => register()} />
</View>

</View>
</View>
);
}

La parte de estilos no se cambia.

Al ingresar valores en el formulario y dar clic en el botón se reciben los valores en la


terminal, en formato JSON:

Separar las hojas de estilos

En la carpeta “home” crear un archivo “Styles.tsx”, cortar y pegar los estilos dentro de
“home.tsx” y modificar así:
import { StyleSheet } from "react-native";

const HomeStyles = StyleSheet.create({


container: {
flex: 1,
backgroundColor: 'black',
},
imageBackground: {
width: '100%',
height: '100%',
opacity: 0.7,
bottom: '30%',
},
form: {
width: '100%',
height: '40%',
backgroundColor: 'white',
position: 'absolute',
bottom: 0,
borderTopLeftRadius: 40,
borderTopRightRadius: 40,
padding: 30,
},
formText: {
fontWeight: 'bold',
fontSize: 16,
},
formRegister: {
flexDirection: 'row',
justifyContent: 'center',
marginTop: 30,
},

formRegisterText: {
fontStyle: 'italic',
color: 'orange',
borderBottomWidth: 1,
borderBottomColor: 'orange',
fontWeight: 'bold',
marginLeft: 10,
},
logoContainer: {
position: 'absolute',
alignSelf: 'center',
top: '15%',
},
logoImage: {
width: 100,
height: 100,
},
logoText: {
color: 'white',
textAlign: 'center',
fontSize: 20,
marginTop: 10,
fontWeight: 'bold',
},
});

export default HomeStyles;

Modificar el archivo “home.tsx”:

import React, { useState} from 'react';


import { useNavigation } from '@react-navigation/native';
import { View, Text, StyleSheet, Image, TextInput, ToastAndroid, Touchable,
TouchableOpacity } from 'react-native';
import { RoundedButton } from
'../../../Presentation/components/RoundedButton';
import { StackNavigationProp } from '@react-navigation/stack';
import { RootStackParamList } from '../../../../App';
import useViewModel from './ViewModel';
import { CustomTextInput } from '../../components/CustomTextInput';
import styles from './Styles';

export const HomeScreen = () => {


const {email, password, onChange} = useViewModel();
const navigation =
useNavigation<StackNavigationProp<RootStackParamList>>();

return (
<View style={styles.container}>
<Image
source={require('../../../../assets/chef.jpg')}
style={styles.imageBackground}
/>
<View style={styles.logoContainer}>
<Image
source={require('../../../../assets/logo.png')}
style={styles.logoImage}
/>
<Text style={styles.logoText}>FOOD APP</Text>
</View>

<View style={styles.form}>
<Text style={styles.formText}>INGRESAR</Text>

<CustomTextInput
image= {require('../../../../assets/email.png')}
placeholder='Correo electrónico'
keyboardType='email-address'
property='email'
onChangeText={onChange}
value={email}
/>
<CustomTextInput
image= {require('../../../../assets/password.png')}
placeholder='Contraseña'
keyboardType='default'
property='password'
onChangeText={onChange}
value={password}
secureTextEntry={true}
/>

<View style={{ marginTop: 30 }}>


<RoundedButton text='ENTRAR' onPress={() =>{
console.log('Email: ' + email);
console.log('Password: ' + password);
}} />
</View>

<View style={styles.formRegister}>
<Text>¿No tienes cuenta?</Text>
<TouchableOpacity onPress={() =>
navigation.navigate('RegisterScreen')}>
<Text
style={styles.formRegisterText}>Regístrate</Text>
</TouchableOpacity>
</View>

</View>
</View>
);
}

Realizar lo mismo en la carpeta “registro”.

También podría gustarte