Í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.
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 Offline 聽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
conSequelize
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
yReact
.
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.
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.
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.
Espero que te sirva, gracias por leer este post.
A帽adir comentario