Recientemente, publicamos una serie de artículos sobre el tema del uso de Couchbase Lite en una aplicación React Native. En este tutorial, lo llevarás un paso más allá y usarás el recomendado Módulo Couchbase Lite para React Native (disponible como Módulo npm). Añadirás el código necesario de Couchbase Lite para completar las Pantallas de Login y Lista para una simple Aplicación Todo. Al final del tutorial, habrás cubierto los siguientes conceptos básicos:
- Crear, suprimir una base de datos y los documentos que contiene.
- Uso de Couchbase Views para mostrar documentos de la lista por fecha.
- Replicaciones con autenticación básica.
- Creación de usuarios de Sync Gateway y uso de una función de sincronización.
Requisitos
- Node.js 4.0 +
- Xcode 7 o superior
- Un simulador de iOS o un dispositivo con iOS 9 o superior
Primeros pasos
Para ahorrar algo de tiempo, ya he creado un proyecto de inicio que contiene todo el código de interfaz de usuario. Adelante descargarlo al directorio que prefieras y descomprime el contenido. A continuación, desde el directorio del proyecto instale las dependencias:
1 |
$ npm instale |
Si aún no es el caso, asegúrate también de tener la CLI de React Native instalada globalmente:
1 |
$ npm instale reaccionar-nativo -g |
A continuación, inicie el demonio React Native:
1 |
$ reaccionar-nativo iniciar |
Abra el proyecto Xcode en ios/UntitledTodoApp.xcodeproj
y ejecútalo en el simulador o dispositivo desde Xcode. Deberías ver ambas pantallas:
Observe que el botón Cerrar sesión no le devuelve a la pantalla de inicio de sesión y que no se muestra nada en el ListView. No se preocupe, lo solucionará en la siguiente sección :) Recuerde habilitar LiveReload usando la opción Cmd+D
(y Chrome Debugging puede ser útil a veces).
Persistencia local con Couchbase Lite
El proyecto de inicio ya contiene el módulo React Native Couchbase Lite (puede seguir la guía instrucciones de repo para usarlo en otro proyecto React Native). En esta sección, aprenderás cómo instanciar un nuevo gestor, base de datos y persistir documentos localmente.
Crear un nuevo archivo en src/base.js
y pega lo siguiente:
1 2 3 4 5 6 7 8 9 10 11 |
// 1 importar {director, ReactCBLite} de 'reaccionar-nativo-couchbase-lite'; // 2 ReactCBLite.init(5984, 'admin', 'pase'); // 3 var base de datos = nuevo director('http://admin:pass@localhost:5984/', 'myapp'); // 4 módulo.exportaciones = base de datos; |
El código hace lo siguiente:
- Importe el
director
yReactCBLite
del módulo mediante la función desestructurar la sintaxis de las asignaciones en ES6. - Inicia el Listener de Couchbase Lite que sirve una API REST HTTP que usarás más tarde.
- Instanciar una instancia de gestor pasando la URL del servidor incrustado y el nombre de la base de datos deseada.
- Exporte el objeto para poder utilizarlo durante todo el ciclo de vida de la aplicación.
Ahora puede centrarse en components/Login.js
. Añade una sentencia require para utilizar el objeto de base de datos del paso anterior:
1 |
var base de datos = requiere('./../base de datos'); |
Este componente tiene dos campos de entrada y un botón, por ahora no va a comprobar si el usuario existe porque Sync Gateway no está en funcionamiento todavía. Sin embargo, tendrá que arrancar la base de datos local antes de abrir la vista de lista. Sustituya el cuerpo de onLoginButtonPressed
con lo siguiente:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
var remoto = `http://${este.estado.nombre.usuario}:${este.estado.contraseña}@localhost:4984/todos`; var credenciales = este.estado; base de datos.crearBaseDeDatos() .entonces((res) => { base de datos.replicar('myapp', remoto, verdadero); base de datos.replicar(remoto, 'myapp', verdadero); var todoViews = { enumera: { "mapa": función (doc) { emite(doc.fecha_de_creación, doc); }.toString() } }; base de datos.crearDocumentoDeDiseño("_diseño/todo", todoViews); }).captura((err) => { tirar err }); var datos = {nombre de usuario: credenciales.nombre de usuario}; este.atrezzo.navegador.pulse({id: 2, datos: datos}); |
Aquí, está creando la base de datos y luego registrando un documento de diseño con una vista para consultar documentos por su fecha_de_creación
propiedad.
A continuación, abra Listas.js
y requerir el objeto de base de datos una vez más:
1 |
var base de datos = requiere('./../base de datos'); |
En el render
observe las 2 variables leftButtonConfig
y rightButtonConfig
que se utilizan en el componente NavigationBar en la sentencia return. Corresponden a la Cerrar sesión y Nuevo botones. Los manejadores de clic no hacen nada sin embargo, por lo que va a cambiar de inmediato. En la ventana manipulador
campo del objeto literal leftButtonConfig
añadir:
1 2 3 4 5 6 |
base de datos.borrarBaseDeDatos() .entonces((res) => { si (res.ok) { este.atrezzo.navegador.pop(); } }); |
Simplemente está borrando la base de datos (y todos los documentos y posibles réplicas en curso con ella) y volviendo a la vista de inicio de sesión.
A continuación, en el manipulador
para la rightButtonConfig
añadir:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
AlertIOS.alerta( 'Nuevo Lista Título', null, [ { texto: 'Guardar', onPrensa: (texto) => { base de datos.crearDocumento({ tipo: 'lista', título: texto, propietario: que.atrezzo.datos.nombre de usuario, fecha_de_creación: nuevo Fecha().getTime() }); } }, { texto: 'Cancelar', estilo: 'cancelar' } ], 'llano-texto' ); |
En este caso, se muestra un cuadro de diálogo de alerta para introducir el nuevo título de la lista y, a continuación, se mantiene en la base de datos (con la función propietario
con el usuario conectado y fecha_de_creación
como marca de tiempo actual).
A continuación, debajo del getInitialState
añada lo siguiente para consultar los documentos almacenados:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
_redrawListView: función() { // 1 base de datos.queryView('_diseño/todo', 'enumera') .entonces((res) => { este.setState({ fuente de datos: este.estado.fuente de datos.cloneWithRows(res.filas) }); }); }, componentWillMount: función() { // 2 var que = este; que._redrawListView(); este.intervalo = setInterval(función () { que._redrawListView(); }, 100); }, // 3 componentWillUnmount: función() { clearInterval(este.intervalo); }, |
He aquí el desglose de lo que está ocurriendo:
_redrawListView
es un método privado que consulta elenumera
y actualiza la fuente de datos para mostrar las nuevas filas (si las hay) en la pantalla.- En
componentWillMount
está utilizando elsetInterval
para comprobar periódicamente si hay nuevos documentos y actualizar la interfaz de usuario. - Detener el método de intervalo cuando el componente se desmonta (es decir, al volver a la vista de inicio de sesión).
Cree una nueva lista y abra http://localhost:5984/myapp/_design/todo/_view/lists en su navegador. Debe proporcionar admin
para el nombre de usuario y pase
para la contraseña. La respuesta JSON debería tener este aspecto:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
{ "offset":0, "filas":[ { "llave":1452038776654, "valor":{ "propietario":"james", "_id":"-_XbsYkL8LNqVDSMuZceW71", "_rev":"1-e62876578d58bcdef321bb50470debf4", "fecha_creada":1452038776654, "título:"Comestibles", "tipo":"lista", "_local_seq":2 }, "id":"-_XbsYkL8LNqVDSMuZceW71" }, ... ], "total_rows":2 } |
Para visualizarlos en la pantalla se utilizará el botón ListView
componente. Tiene dos atributos obligatorios:
fuente de datos
para proporcionar los datos: puede pasarthis.state.dataSource
.renderRow
toma una función que devuelve unVer
dado un elemento de la lista.
Te falta el método para dibujar la fila, abajo render
añada un renderRow
con lo siguiente:
1 2 3 4 5 6 7 8 9 |
renderRow: función(lista) { var lista = lista.valor; devolver ( {lista.título} {lista.propietario} ); } |
Los datos deseados se guardan en el valor
y está mostrando los campos de título y propietario en Texto
elementos. En la sentencia return del render
añada el método ListView
por debajo del Barra de navegación
componente así:
1 2 3 4 |
Persiste en los documentos y observa que la pantalla se actualiza sola:
Configuración de la pasarela de sincronización
En esta sección, utilizará Sync Gateway para introducir la sincronización bidireccional y la autenticación de usuarios en el servidor, de modo que puedan iniciar sesión varios usuarios. En primer lugar, descargue Sync Gateway de aquí y en el directorio raíz del proyecto, cree un nuevo archivo llamado sync-gateway-config.json
con el siguiente JSON:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
{ "log": ["*"], "bases de datos": { "todos": { "usuarios": { "moderador": {"contraseña": "pase", "admin_canales": ["*"]}, "laura": {"contraseña": "pase"}, "james": {"contraseña": "pase"}, "adam": {"contraseña": "pase"} }, "sync": `función(doc, oldDoc) { var channelname = "chan_" + doc.propietario canal(channelname); acceda a(doc.propietario, channelname); }` } } } |
Algunas cosas importantes a tener en cuenta aquí son:
- En
INVITADO
está desactivado (de hecho, es el caso por defecto) por lo que cualquier petición no autenticada será tratada como no autorizada y devolverá un código de estado 401. Para ello, se han creado 4 usuarios diferentes (con nombres moderador, laura, james, adam). El usuario llamado moderador tiene acceso a todos los canales. - La función de sincronización envía un documento a un canal denominado
propietario
campo y concede elpropietario
acceso a ese canal.
Así que, en teoría, el moderador debería ver todos los documentos de la Lista, mientras que el otros usuarios sólo verán sus propios documentos de la Lista.
Inicie Sync Gateway desde la línea de comandos:
1 |
$ ~/Descargas/couchbase-sincronizar-pasarela/papelera/sincronizar_pasarela ./sincronizar-pasarela-config.json |
En Iniciar sesión.js
actualice el onLoginButtonPressed
como sigue:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
// 1 - Solicitar configuración var remoto = `http://${este.estado.nombre.usuario}:${este.estado.contraseña}@localhost:4984/todos`; var credenciales = este.estado; var ajustes = { método: 'POST', cabeceras: { 'Contenido-Tipo': 'aplicación/json' }, cuerpo: JSON.stringify({ nombre: credenciales.nombre de usuario, contraseña: credenciales.contraseña }) }; var que = este; // 2 - Comprobar que el nombre y la contraseña son válidos buscar(remoto + '/_sesión', ajustes) .entonces((res) => { interruptor (res.estado) { caso 200: // 3 - Aplicación Bootstrap base de datos.crearBaseDeDatos() .entonces((res) => { base de datos.replicar('myapp', remoto, verdadero); base de datos.replicar(remoto, 'myapp', verdadero); var todoViews = { enumera: { "mapa": función (doc) { emite(doc.fecha_de_creación, doc); }.toString() } }; base de datos.crearDocumentoDeDiseño("_diseño/todo", todoViews); }).captura((err) => { tirar err }); var datos = {nombre de usuario: credenciales.nombre de usuario}; que.atrezzo.navegador.pulse({id: 2, datos: datos}); romper; caso 401: // 4 - Credenciales incorrectas alerta('Usuario no encontrado o contraseña incorrecto'); romper; por defecto: romper; } }); |
Esto es lo que ocurre:
- Construya la URL de la base de datos remota (en este caso se trata de una base de datos de Sync Gateway) y establezca los campos JSON de nombre/contraseña en el cuerpo de la solicitud.
- Utiliza el POST /_sesión para comprobar el nombre y la contraseña con Sync Gateway.
- Si las credenciales son válidas, cree la base de datos y, una vez hecho esto, inicie las réplicas continuas push/pull y registre un documento de diseño con una vista para consultar el documento por su
fecha_de_creación
propiedad. - Si las credenciales no son válidas, muestra una ventana de alerta.
Ejecute la aplicación e inicie sesión como usuarios diferentes. Si es posible, ejecuta la app en dos dispositivos para observar la replicación continua y los diferentes permisos de lectura del moderador:
Conclusión
En este tutorial, aprendiste a usar el módulo React Native Couchbase Lite para construir una simple aplicación Todo donde múltiples usuarios pueden iniciar sesión.
El proyecto final puede consultarse en GitHub.
No dudes en compartir tus opiniones, hallazgos o preguntas en los comentarios o en los foros. ¡Hasta pronto!
Hola James,
parece que este tutorial ya está obsoleto, ya que
import {manager, ReactCBLite} from 'react-native-couchbase-lite'
devuelve undefined para ReactCBLite.
¿Podrías por favor actualizar o indicar algún tutorial real donde las operaciones CBL desde la perspectiva JS se describan de una manera tan limpia y completa como lo has hecho en este post?