React Native nos permite crear aplicaciones reales nativas para iOS y Android basado en React JS. Utilizando ReactJS, en lugar de obtener una aplicación web híbrida, obtenemos una aplicación real nativa.
Una aplicación híbrida es aquella que ejecuta código HTML, CSS y Javascript dentro de un componente de la aplicación móvil destinado a cargar páginas web (una especie de iframe). Una aplicación nativa es la que está programada utilizando el lenguaje nativo de la plataforma.
El código que programemos usando React Native será traducido al lenguaje nativo de la plataforma, mientras que cuando desarrollamos una aplicación híbrida, ejecutamos código HTML, CSS y JavaScript dentro de esta especie de iframe.
Para programar una aplicación nativa para Android, necesitaríamos conocer el lenguaje Kotlin, mientras que si la aplicación es para IOS, necesitaríamos saber Swift. Sin embargo, con React Native, podremos realizar una aplicación nativa para ambas plataformas conociendo una sola tecnología.
Las aplicaciones nativas, respecto de las aplicaciones híbridas, tienen:
- Mejor rendimiento
- Menor consumo de memoria.
- Mayor velocidad.
Crear una aplicación en React Native con Expo
El siguiente comando creará una aplicación que utilizará la navegación expo router.
npx create-expo-app .
Si quisieramos utilizar la navegación de React Navigation, ejecutaríamos el siguiente comando.
npx create-expo-stack --react-navigation .
Si quisieramos escoger el tipo de plantilla a partir de la cual crearemos nuestra aplicación, ejecutaremos el siguiente comando:
npx create-expo-app . --template
Ejecutar nuestra aplicación de Expo
1. Ejecutamos el proyecto que hemos creado
npm start
2. Instalamos la aplicación Expo en el teléfono móvil: Expo
5. Para desplegar escanearemos el código qr generado. Para evitar problemas…
- En el teléfono móvil Android, iremos a ajustes → Aplicaciones → Expo → Mostrar sobre otras apps.
- Es probable que tengas actualizar el método start del package.json para añadir la opción de tunnel:
"scripts": {
"start": "expo start --tunnel",
...
},
Solución de errores al ejecutar
- CommandError: ngrok tunnel took too long to connect
Menú de inicio de windows → Windows Security → Virus & threat protection → Virus & threat protection settings → Manage settings → Real-time protection → Off
Actualizar Expo
Algunos problemas utilizando expo pueden solucionarse simplemente actualizándolo:
expo upgrade
Instalación de módulos en un proyecto de Expo
No debemos instalar los módulos utilizando npm, ya que este gestor de dependencias, por defecto, instala siempre la última versión del módulo y puede ocurrir que esta no sea compatible con la versión de Expo que estamos usando. En lugar del comando npm, utilizaremos el comando expo.
npx expo install nombre-modulo
Ejecutando la aplicación en el emulador
1. Debemos tener instalado Android Studio.
2. Si estamos usando windows, tendremos que añadir las siguientes variables de entorno a nivel de sistema.
ANDROID_HOME → C:\Users(name)\AppData\Local\Android\Sdk
Añadir al Path → C:\Users(name)\AppData\Local\Android\Sdk\platform-tools
Esto evitarárá el típico error:
ADB no se reconoce como un comando interno o externo.
2. Creamos y arrancamos un nuevo Device Manager:
Componentes básicos de React Native
View
Equivalente a los div de HTML. Sirve para agrupar componentes.
import { View } from 'react-native';
<View><View>
Text
import { Text } from 'react-native';
<Text>El texto<Text>
TextInput
<TextInput onChangeText={text => setStateValue(text)}/>
Image
import { Image } from 'react-native';
import image from 'ruta-imagen/image.png';
<Image source={image} />
Scroll
El componente SafeAreaView evita que el contenido se meta por debajo de la status bar.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Pressable
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Listado de elementos:
Este componente permite renderizar sólo los elementos de la lista que se están viendo en pantalla, siendo más óptimas que usar combinaciones de etiquetas <View> y <Text> dentro de un map cuando tengamos un listado de muchos elementos.
El atributo keyExtractor es utilizado para identificar de manera inequivoca a cada registro, igual que hacíamos con el atributo key cuando usábamos un map en ReactJS.
El atributo numRows no actualiza los cambios on The Fly o en caliente, lo cual significa que tendrás que volver a ejecutar la aplicación para que el cambio surta efecto.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Configuración de firebase en expo
En este enlace tienes una configuración adicional que debes codificar en el firebase.js para mantener los datos del usuario logueado cuando utilizas firebase con expo:
https://github.com/expo/fyi/blob/main/firebase-js-auth-setup.md
Debemos instalar el siguiente módulo:
npx expo install @react-native-async-storage/async-storage
Nuestra configuración quedaría así:
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
styled-components en react-native
Es posible utilizar Styled Components en React native sin ningún tipo de limitación. Sin embargo, para maquetar los componentes en React Native, hemos de tener en cuenta lo siguiente:
- El valor por defecto el estilo display es flex. Los posibles valores de este estilo son: flex y none.
- El valor por defecto del estilo flex-direction es column, al contrario de lo que ocurre en una aplicación web, es es row.
- La unidad de medida que usaremos será px. Ni %, ni em, ni rem.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Al usar styled-components en React native no puedes mezclarlos con estilos nativos en línea. El siguiente ejemplo sería incorrecto:
<MyStyledComponent style={{marginTop:'6px'}} />
Media queries
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Cargar tipografías
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Módulos útiles
React native vector icons
npx expo install react-native-vector-icons
Permite incrustar iconos en nuestra aplicación pertenecientes a múltiples colecciones de iconos.
import Icon from 'react-native-vector-icons/Ionicons';
...
<Icon name="rocket" size={30} color="#900" />
Esta es la lista de iconos disponibles con su correspondiente codigo que lo carga:
https://oblador.github.io/react-native-vector-icons/
https://www.npmjs.com/package/react-native-vector-icons
expo-av
Permite cargar un video en el background.
npx expo install expo-av
https://docs.expo.dev/versions/latest/sdk/av/
React native svg
npx expo install react-native-svg
Expo Image Picker
npx expo install expo-image-picker
Permite seleccionar imágenes de la galería de fotos.
https://docs.expo.dev/versions/latest/sdk/imagepicker/
React native modal
npx expo install react-native-modal
Cargaremos una librería externa para hacerlo.
React native maps
npx expo install react-native-maps
Integra un mapa de google maps en nuestra aplicación.
https://docs.expo.dev/versions/latest/sdk/map-view/
Date Time Picker
npx expo install @react-native-community/datetimepicker
Permite seleccionar fechas.
https://www.npmjs.com/package/@react-native-community/datetimepicker
React Native Sign In
Este módulo no funciona con Expo GO. Tendremos que usarlo utilizando una Development Build
https://www.npmjs.com/package/@react-native-google-signin/google-signin
Paquetes de elementos de la user Interface
React native elements
Native Base
Expo camera
npx expo install expo-camera
Habrá que establecer una configuración en el fichero app.json para poder hacer las fotos.
/app.json
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
/src/components/CameraComponent.js
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
/src/screens/Home.js
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
https://www.npmjs.com/package/expo-camera
<BottomTab.Screen name="Nombre Screen 1" component={StackNav}
Ejercicio React Native
Listado
Hacer una aplicación que cargue un array de de elementos en un FlatList y tenga un cuadro de texto que le permita al usuario podrá añadir nuevos elementos.
Tener en cuenta que para detectar cuando un texto cambia dentro de un input usaremos onChangeText en lugar de onChange.
<TextInput onChangeText={text => setTxt(text)} />
Expo router
Este sistema de navegación utiliza React Navigation internamente (documentado más abajo). Es mucho más sencilla de usar y es mi opción recomendada.
Para poder usarlo, debemos instalarlo:
npx expo install expo-router
Cuando usamos expo-router debemos cambiar el punto de entrada a la aplicación. Para ello, remplazaremos la propiedad main del package.json de nuestra plantilla blank por la siguiente propiedad main. Después de esto, podremos borrar el fichero App.js.
/package.json
{
"name": "react native app",
"version": "1.0.0",
"main": "expo-router/entry",
...
Con Stack Navigation
Estableceremos la configuración de la navegación principal en este fichero:
/app/_layout.jsx
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
/app/(stack)/_layout.jsx
import { Stack } from "expo-router";
const _layout = () => {
return (
<Stack>
<Stack.Screen name="Page1" />
<Stack.Screen name="Page2" />
</Stack>
);
};
export default _layout;
Las screens por las que navegaremos estarán dentro de la carpeta app. La screen donde se inicia la navegación debe llamarse index.js. Sólo debe haber una página de inicio (index.jsx), que estará en (stack), (drawer) o (bottom) según nos convenga.
Independientemente de cual sea el primer Stack del layout, index.js será el punto de inicio de la aplicación.
/app/(stack)/index.js
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
/app/(stack)/Home2.js
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Paso de parámetros en Stack Navitagion
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Con Drawer Navigation
Debemos instalar las siguientes dependecias:
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Y utilizar el siguiente código:
/src/app/(drawer)/_layout.jsx
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Con Bottom Navigation
/app/index.js
El fichero de la configuración de las tabs debe estar en una carpeta llamada (tabs).
Expo irá a buscar la navegación por tabs sólo si no existe un fichero index.js en la raíz de la carpeta app.
/app/(tabs)/_layout.jsx
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
El fichero index.jsx será el que se cargue por defecto en una navegación con tabs. Es un fichero necesario.
/app/(tabs)/index.jsx
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
/app/(tabs)/Page2.jsx
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
React Navigation
Ten en cuenta que es probable que esta navegación de problemas cuando la ejecutemos en en el navegador web.
Instalación de las dependencias del core de react navigator:
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Stack Navigation
La stack navigation es similar a la que realizamos en nuestro navegador web mediante los botones de avanzar y retroceder página.
Imagina que tu aplicación móvil tiene tres páginas: A, B y C. Empiezas tu navegación en la página A. Pulsas un botón que te lleva a la página B. El stack queda así: B, A y C. Además, aparece el botón en pantalla de ir a la página anterior, en este caso, la página A. Si lo pulso, el stack quedaría así: A, B y C. Si pulso en ir a la página C, el stack quedaría así: C, A, B. Nuevamente, si pulso en ir a la página anterior, iríamos a la página A y la página C quedaría en la última posición. El stack quedaría así: A, B y C.
Si una navegación esta vinculada a una pantalla (como la stack navitation que estamos creando en este paso), la carpeta de navegación estará dentro de la carpeta de la pantalla. Si una navegación es global (como la bottom navigation que crearemos más adelante), estará en la carpeta navigation.
Instalación de las dependecias expecíficas de stack navigation:
npx expo install @react-navigation/stack
/App.js
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
/src/navigation/index.js
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
/src/screens/Page1.jsx
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Paso de parámetros
Envío:
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Recogida:
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Bottom Navigation
Vamos a interar la Bottom Navigation dentro del StackNavigation principal.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
/src/navigation/index.js
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
/src/navigation/bottom/index.jsx
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Integrando una Stack Navigation en la Bottom Navigation que está dentro de la Stack Navigation principal
Añadiremos una StackNavigation a la BottomNavigation:
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import BottomScreen1 from '../../screens/BottomScreen1';
import AnotherNavigationfrom 'navigation/stack/AnotherNavigation';
const BottomTab = createBottomTabNavigator();
const BottomNav = () => (
<BottomTab.Navigator>
<BottomTab.Screen name="Nombre Screen 1" component={BottomScreen1} />
<BottomTab.Screen name="Nombre Screen 2" component={AnotherNavigation} options={{ headerShown: false }} />
</BottomTab.Navigator>
);
export default BottomNav;
La nueva StackNavigation que hemos importado en la BottomNavigation, podría tener este código:
import { createStackNavigator } from '@react-navigation/stack';
import Page2 from '../../screens/Page2';
import BottomScreen2 from '../../screens/BottomScreen2';
const Stack = createStackNavigator();
const AnotherNavigation = () => {
return (
<Stack.Navigator>
<Stack.Screen
name="BottomScreen2"
component={BottomScreen2}
/>
<Stack.Screen
name="Page2"
component={Page2}
options={{ headerShown: false }}
/>
</Stack.Navigator>
);
}
export default AnotherNavigation;
Tenemos dos opciones:
- Modificar el componente BottomTabs para obtener un comportamiento global de todas las screens.
- Modificar el Tab.Screen que nos interese en cada caso.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
/src/navigation/bottom/bottom-config.js
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
En las pantallas individuales, para establecer la configuración, utilizaremos options en lugar de screenoptions.
/src/screen/Page2/screen-config.js
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Cómo utilizar variables de entorno en una aplicación creada con Expo
Utilizaremos la siguiente sintaxis para acceder a una variable de entorno definida en el fichero .env:
process.env.EXPO_PUBLIC_API_KEY // No te olvides del prefijo EXPO_PUBLIC_
Subida de imágenes a Firebase
Utilizaremos el expo-image-picker:
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Geolocalización
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Persistiendo la información
npx expo install @react-native-async-storage/async-storage
https://react-native-async-storage.github.io/async-storage/docs/install/
Podemos usar el siguiente componente para gestionar el valor. Tener en cuenta que debemos almacenar texto (podemos convertir un objeto en texto con JSON.stringify) y que la clave con la que guardamos el valor también debe ser texto.
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Trabajo con mapas: calcular distancias, ver si un punto cae dentro de cierto radio…
https://www.npmjs.com/package/geolib
Compilar / Build
Para Android:
Debemos instalar el siguiente módulo en el sistema operativo:
npm install -g eas-cli
También actualizaremos el fichero package.json con los siguientes scripts:
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Debemos tener el siguiente fichero en la raíz del proyecto:
eas.json
while(premium == false) verCodigo = false;
Para poder ver el código fuente, accede o suscríbete.
Ejecutamos en la terminal el comando:
eas login
Panadería
1. Hacer una screen Home que lea el siguiente fichero de datos y pinte una rejilla utilizando el componente FLatList con cada uno de los elementos.
./data/categories.js
export const CATEGORIES = [
{
id: 1,
name: 'Categoría 1',
color: '#896978'
},
{
id: 2,
name: 'Categoría 2',
color: '#839791'
},
{
id: 3,
name: 'Categoría 3',
color: '#aac0af'
},
{
id: 4,
name: 'Categoría 4',
color: '#896978'
},
]
2. Utilizando Stack Navigation, al pulsar en uno de los elementos de Home, debemos navegar al Screen Productos de la categoría en la que haremos una consulta a Firebase para recuperar los productos correspondientes a la categoría seleccionada.
Puedes alimentar tu aplicación con productos consultando la api de mercadolibre y haciendo una insercción de productos en Firebase a partir de los datos recuperados.
Para pasar parámetros de una pantalla a otra, puedes consultar la documentación que vimos anteriormente.
3. Al pulsar sobre un producto iremos a una tercera screen en la que recuperaremos los datos del mismo.
4. También tendremos la opción de añadir el producto a un carrito. Gestionaremos este carrito utilizando Context API para almacenar los datos.
Para navegar al carrito utilizaremos Bottom Tab Navigator.
El bottom tab navigator tendrá dos menús. Uno enlzará al stack navigator que acabamos de hacer y otro al screen Cart.
5. Debemos tener un stack con dos screens: login y registro. Si el usuario no esta logueado, cargaremos el creen de login, y si no el stack de navegación que ya teníamos:
src/navigation/index.js
import React, { useEffect, useState } from 'react';
import { NavigationContainer } from '@react-navigation/native';
import TabsNavigator from './bottomtabs/TabsNavigator';
import { onAuthStateChanged } from 'firebase/auth';
import { auth } from '../app/firebase';
import AuthScreen from '../screens/AuthScreen';
const MainNavigator = () => {
const [isLogged, setIsLogged] = useState(false);
useEffect(() => {
onAuthStateChanged(auth, user => {
if (user) {
console.log('user', user);
const uid = user.uid;
setIsLogged(true);
} else {
console.log("No user logged");
setIsLogged(false);
}
});
}, []);
return (<NavigationContainer>
{isLogged ?
<TabsNavigator /> :
<AuthScreen />
}
</NavigationContainer>)
}
export default MainNavigator;
Ejecutar sin Expo GO
Creamos el fichero eas.json:
{
"build": {
"development": {
"developmentClient": true,
"distribution": "internal"
},
"preview": {
"distribution": "internal"
},
"production": {}
}
}
package.json:
{
"scripts": {
...
"build-dev": "eas build --platform android --profile development",
},
Cuando ejectutamos esto…
1. Aparecerá un QR en la terminal, que al ser escaneada nos permitirá descargar una aplicación en modo desarrollo.
2. Ejecutamos el comando habitual npm start . Aparecerá un nuevo QR que debemos escanear y seleccionar la opción development build. A partir de aquí, la aplicación se actualizará según hagamos cambios en el código fuente.