Muy buenas, soy Luis y hoy les traigo un artículo.
Índice
Una guía para crear una aplicación de carga de imágenes React Native con capacidades sin conexión
Un requisito común para las aplicaciones móviles es la capacidad sin conexión. Si espera que sus usuarios usen la aplicación en un área con conectividad limitada, entonces es imprescindible tener capacidades sin conexión.
Por ejemplo, la startup para la que trabajo creó una aplicación para recopilar datos de cultivos de los campos. Normalmente, los campos se encuentran en un área bonita y no siempre se garantiza una buena conexión de red. Por lo tanto, necesitamos la capacidad de los usuarios para hacer su trabajo en el campo y luego sincronizar sus datos con el servidor una vez que hayan regresado a un área con mejor conectividad de red.
En este artículo, voy a demostrar cómo crear una aplicación básica de carga de imágenes con capacidades sin conexión. Usaremos React Native y Redux sin conexión en nuestra aplicación de demostración. También crearemos una API NodeJS para aceptar los datos de nuestra aplicación y almacenarlos en una base de datos.
¿Qué estamos construyendo?
En este artículo construiremos lo siguiente:
- Una instancia local de PostgreSQL para almacenar datos
- API NodeJS con Sequelize para comunicarse con la base de datos
- Una aplicación React Native para capturar y cargar imágenes con capacidades sin conexión
Aquí hay una vista previa del resultado final:

Prerrequisitos
Esto es lo que deberá seguir junto con este ejemplo:
- NodeJS instalado
- Docker instalado
- React Native CLI instalado
- Familiaridad con JavaScript y React
Capacidades sin conexión
El camino más fácil para crear una aplicación con capacidades sin conexión es crear la aplicación desde el principio teniendo en cuenta la conexión sin conexión. Es posible agregar a una aplicación existente, pero es mucho más fácil de incluir desde el principio si es algo que sabes que será necesario.
Definitivamente puede construir su propia lógica y servicios para manejar todo en el modo fuera de línea, pero esto puede ser bastante complejo de implementar. En su aplicación, deberá realizar un seguimiento del estado de conexión del dispositivo del usuario y manejarlo en consecuencia. Cuando el usuario hace algo que causaría una actualización, tendría que verificar ese estado y enviarlo al servidor o almacenarlo localmente hasta que se pueda sincronizar en un momento posterior.
En este artículo, usaremos una biblioteca llamada Redux Offline. Esto le resultará muy familiar si alguna vez ha creado una aplicación con Redux, ya que funciona igual. Proporcionamos a Redux Offline la información para sincronizar nuestros datos con el servidor y maneja la sincronización en función del estado actual de la conexión.
Redux Offline hace que sea sencillo para los desarrolladores manejar la capacidad fuera de línea. Compruébalo en Github.
PostgreSQL y Docker
Para almacenar los datos de nuestra aplicación usaremos una base de datos PostgreSQL. Puede ejecutar su instancia en cualquier lugar, pero para este ejemplo, crearé una instancia local usando Docker.
Con Docker instalado, ejecute el siguiente comando en una terminal para extraer la imagen de PostgreSQL de Docker.
docker pull postgres
Eso tomará uno o dos minutos para descargar la imagen, pero una vez que esté completo, ejecute el siguiente comando para iniciar una instancia local.
docker run --name local-postgres -e POSTGRES_PASSWORD=password -d -p 5432:5432 postgres
Esto debería iniciar una instancia local de inmediato. Para confirmar, puede ejecutar el siguiente comando para verificar los procesos actuales de Docker.
docker ps
A continuación, crearemos una nueva base de datos desde el nuevo contenedor que acabamos de comenzar. Ejecute los siguientes comandos.
docker exec -it 16856b6f5f bash
root@16856b6f5f:/# psql -U postgres
postgres=# CREATE DATABASE imageuploads;
postgres=# \q
root@16856b6f5f:/# exit
Ahora tenemos nuestra instancia local lista y una base de datos vacía creada dentro de esa instancia. En la siguiente sección, usaremos Sequelize para crear migraciones para configurar nuestras tablas de base de datos.
API de NodeJS
Crearemos una API NodeJS simple con Express y Sequelize. Express es un marco que se usa para crear API REST y Sequelize es un ORM que usaremos para comunicarnos con nuestra base de datos PostgreSQL. En la API, crearemos puntos finales para crear nuevas entradas para cargas de imágenes y también para obtener una lista de todas las cargas de imágenes que se encuentran actualmente en la base de datos.
Para comenzar, crearemos un nuevo proyecto NodeJS vacío. Ejecute los siguientes comandos en una terminal para configurar un package.json vacío y luego agregue nuestras dependencias.
mkdir offline-uploads-api
cd offline-uploads-api
npm init -y
npm install --save express sequelize pg pg-hstore cors body-parser
npm install --save-dev sequelize-cli
A continuación, inicializaremos la configuración de Sequelize ejecutando el siguiente comando.
npx sequelize-cli init
Esto creará algunas carpetas nuevas en nuestro proyecto:
config/
models/
migrations/
seeders/
Crearemos nuevos modelos y migraciones aquí en breve, pero primero, debemos agregar nuestra instancia local de PostgreSQL a la configuración de desarrollo en config/config.json
Ahora Sequelize sabe dónde encontrar nuestra base de datos para que podamos crear una tabla donde almacenaremos todas nuestras cargas de imágenes. Usaremos el siguiente comando para crear un modelo y una migración para la uploads
tabla.
npx sequelize-cli model:generate --name uploads --attributes id:bigint,file_name:string,image:blob
Esto generará un modelo al que realizaremos un par de actualizaciones. Actualice el contenido de models / uploads.js al siguiente código.
Para nuestro ejemplo, almacenaremos las imágenes como cadenas base64 en la base de datos. Este es un enfoque válido para almacenar imágenes, también existe la opción de usar algo como S3 para manejar el almacenamiento de archivos.
Además, asegúrese de actualizar la migración para agregar la uploads
tabla a la base de datos con el siguiente código.
Para ejecutar la migración y agregar la tabla a la instancia de la base de datos local, ejecute el siguiente comando que ejecutará todo en la carpeta de migraciones que aún no se haya aplicado a la base de datos.
npx sequelize-cli db:migrate
Después de que esto se ejecute correctamente, deberíamos poder consultar nuestra base de datos y ver que tenemos una sola tabla, ahora el nombre de las cargas con cinco columnas y actualmente no tiene filas de datos.
Ahora que tenemos la base de datos lista, estamos listos para agregar los puntos finales de la API para crear y obtener cargas. Crearemos los siguientes puntos finales:
POST /uploads
GET /uploads
Creemos esos ahora. Crearemos un nuevo archivo en route / uploads.js y agregaremos el siguiente código.
Muy simple como veis. Creamos dos puntos finales y escribimos o buscamos registros en la base de datos. Solo un archivo más para terminar nuestra API. Creamos un nuevo archivo llamado index.js.
Y ese es todo el código que necesitamos para API. Llamaremos a la API en la siguiente sección desde nuestra aplicación móvil. Puede ejecutar la API ejecutando el siguiente comando.
node index.js
React Native y Redux sin conexión
Con todo lo demás en su lugar, ahora podemos pasar a construir nuestra interfaz de usuario. El primer paso es generar una nueva aplicación React Native utilizando la CLI de React Native. Ejecute el siguiente comando en una terminal para iniciar esto.
npx react-native init OfflineImageUpload
Esto tomará unos minutos para crear la nueva aplicación, pero una vez que esté completo, podemos movernos al directorio del proyecto e instalar las dependencias que necesitaremos para implementar Redux Offline.
cd OfflineImageUpload npm install --save redux react-redux @redux-offline/redux-offline@native @react-native-community/async-storage @react-native-community/netinfo react-native-image-pickernpx pod-install
Ese último comando vinculará todo para las aplicaciones nativas. Puede ejecutar la aplicación en el simulador de iOS con el siguiente comando.
npx react-native run-ios
La estructura de directorio que estamos usando para la aplicación probablemente le resultará familiar si alguna vez ha trabajado en una aplicación Redux. Creamos los siguientes directorios en la raíz del proyecto:
- comportamiento/
- componentes /
- contenedores /
- reductores /
Comenzaremos creando las acciones de Redux para nuestra aplicación. Entonces, las acciones son las funciones que usamos para actualizar el estado actual del almacén de datos de la aplicación. Crea un archivo en actions/index.js y agregue el siguiente código.
Este es el lugar donde configuramos Redux Offline. Decoramos las acciones con decoradores fuera de línea para especificar los puntos finales para llamar a las acciones y qué datos pasar. Se pueden desencadenar diferentes acciones en función de si se llama a la API o falla. Si se determina que la conexión de red está fuera de línea, esperará a que se restaure la conexión antes de enviar todas las acciones no confirmadas a la API.
A continuación, necesitaremos crear un reductor que contenga la lista de cargas y consuma los resultados de las acciones que creamos anteriormente. Cree un nuevo archivo en reducers/uploads.js y agregue los siguientes contenidos.
Normalmente, creamos un reductor de raíces para combinar todos nuestros reductores. Solo tenemos uno, pero seguiremos la convención, ya que lo deja abierto para que podamos agregar más fácilmente más adelante. Crea un archivo en reducers/uploads.js y agregue este código.
A continuación, necesitamos un componente donde podamos mostrar la lista de imágenes junto con una forma de cargar imágenes adicionales. Crea un archivo en components/UploadList.js y llénelo con estos contenidos.
import React, {useEffect} from 'react'; import {ScrollView, View, Image, Text, StyleSheet, Button} from 'react-native'; import ImagePicker from 'react-native-image-picker'; function UploadList({uploads, fetchUploads, addUpload}) { useEffect(() => { fetchUploads(); }, []); const openImagePicker = () => { const options = { title: 'Select An Image', storageOptions: { skipBackup: true, path: 'images', }, }; ImagePicker.launchImageLibrary(options, response => { if (!response.didCancel && !response.error) { const source = 'data:image/jpeg;base64,' + response.data; addUpload(response.fileName, source); } }); }; return ( <ScrollView> <Button title="Upload New Image" onPress={openImagePicker} /> {uploads.map((upload, index) => ( <View key={index}> <Image style={styles.image} source={{uri: upload.image}} /> </View> ))} </ScrollView> ); } const styles = StyleSheet.create({ label: { fontWeight: 'bold', marginBottom: 5, }, image: { width: '100%', height: 300, borderWidth: 1, borderColor: 'black', marginBottom: 10, }, }); export default UploadList;
Puedes ver en este componente que estamos esperando. uploads
, fetchUploads
y addUploads
para pasar como accesorios. Lo haremos en el siguiente paso cuando creemos un contenedor para mapear nuestras acciones y reductor a los accesorios de este componente.
Ahora estamos listos para crear un contenedor que unirá nuestras acciones y reductor. Crea un archivo llamado containers/UploadListContainer.js y agregue el siguiente código.
import {connect} from 'react-redux'; import {fetchUploads, addUpload} from '../actions'; import UploadList from '../components/UploadList'; const mapStateToProps = state => { return { uploads: state.uploads, }; }; const mapDispatchToProps = dispatch => { return { fetchUploads: () => { dispatch(fetchUploads()); }, addUpload: (file_name, image) => { dispatch(addUpload(file_name, image)); }, }; }; const UploadListContainer = connect( mapStateToProps, mapDispatchToProps, )(UploadList); export default UploadListContainer;
Aquí hemos mapeado tanto el estado (reductores) como el envío (acciones) a los accesorios para el UploadList
componente que acabamos de crear.
Eso es todo por los componentes que tenemos que crear para la aplicación. Ahora solo atamos el resto en nuestro principal archivo App.js.
import React from 'react'; import { SafeAreaView, StyleSheet, ScrollView, View, Text, StatusBar, } from 'react-native'; import {createStore} from 'redux'; import {offline} from '@redux-offline/redux-offline'; import offlineConfig from '@redux-offline/redux-offline/lib/defaults'; import {Provider} from 'react-redux'; import reducer from './reducers'; import UploadListContainer from './containers/UploadListContainer'; const store = createStore(reducer, offline(offlineConfig)); function App() { return ( <Provider store={store}> <StatusBar barStyle="dark-content" /> <SafeAreaView> <UploadListContainer /> </SafeAreaView> </Provider> ); } export default App;
Aquí simplemente tiramos del contenedor que acabamos de crear y lo mostramos en la interfaz de usuario. También configuramos nuestra tienda Redux con el middleware fuera de línea proporcionado por Redux Offline.
Eso se encarga del código para que nuestra aplicación funcione. Vea nuestra obra a continuación.
Consulte el código de ejemplo en Github:
Eso resume las cosas para este ejemplo. Si está interesado en crear aplicaciones móviles sin conexión, espero que esto le haya dado una idea de un camino simple para hacerlo.
Gracias por leer.
Añadir comentario