Volver al Blog
AppsDesarrolloSoftware

Arquitectura Offline-First en Apps Móviles con React Native, Expo y SQLite

Brayan Developer
4 min de lectura
Arquitectura Offline-First en Apps Móviles con React Native, Expo y SQLite
Cómo diseñar aplicaciones móviles que funcionen al 100% sin conexión a internet y sincronicen datos automáticamente en segundo plano utilizando React Native, Expo y SQLite.

En sectores como logística, inspecciones de campo, minería, ventas en ruta o delivery, la conectividad a internet móvil suele ser intermitente o inexistente. Diseñar bajo el paradigma Offline-First garantiza que tu aplicación móvil nunca se congele y continúe funcionando con total fluidez en cualquier circunstancia.

Portada

¿Qué significa realmente construir una App Offline-First?#

El enfoque tradicional de desarrollo móvil (Online-First) asume que la red siempre está disponible. Si el usuario pierde la señal 4G/5G, la app muestra una pantalla de error o spinners infinitos, bloqueando la captura de datos esenciales.

Por el contrario, una arquitectura Offline-First invierte la jerarquía de persistencia:

  1. La base de datos local es la única fuente de verdad inmediata de la interfaz (UI): Toda lectura o escritura se realiza instantáneamente sobre un motor local embebido (SQLite con expo-sqlite, WatermelonDB o PowerSync).
  2. La sincronización con el servidor backend ocurre en segundo plano: Un motor de sincronización (Sync Engine) detecta la conectividad y transmite los cambios pendientes en lotes estructurados.
  3. Resolución de conflictos determinista: Si dos usuarios modifican el mismo registro mientras uno de ellos estaba offline, se aplican estrategias como Last-Write-Wins (LWW) o control de versiones por marcas de tiempo (CRDTs).

Estructura de la Base de Datos Local con expo-sqlite#

Con el nuevo API síncrono y promesas de expo-sqlite, gestionar bases de datos relacionales en dispositivos iOS y Android es extremadamente rápido y seguro:

// src/lib/db.ts
import * as SQLite from "expo-sqlite";

export const db = SQLite.openDatabaseSync("app_offline.db");

export function initDatabase() {
  // Tabla de órdenes de trabajo con estado de sincronización
  db.execSync(`
    PRAGMA journal_mode = WAL;
    
    CREATE TABLE IF NOT EXISTS work_orders (
      id TEXT PRIMARY KEY NOT NULL,
      client_name TEXT NOT NULL,
      status TEXT NOT NULL,
      notes TEXT,
      created_at INTEGER NOT NULL,
      updated_at INTEGER NOT NULL,
      sync_status TEXT DEFAULT 'pending' -- 'pending' | 'synced' | 'conflict'
    );

    CREATE TABLE IF NOT EXISTS sync_queue (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      table_name TEXT NOT NULL,
      record_id TEXT NOT NULL,
      action TEXT NOT NULL, -- 'INSERT' | 'UPDATE' | 'DELETE'
      payload TEXT NOT NULL,
      timestamp INTEGER NOT NULL
    );
  `);
}

El Patrón de Cola de Sincronización (Sync Queue)#

Cuando el usuario crea o edita un registro en modo offline, ejecutamos una transacción atómica que actualiza la tabla local y encola la mutación:

// src/services/workOrders.ts
import { db } from "@/lib/db";
import * as Crypto from "expo-crypto";

export function createWorkOrder(clientName: string, notes: string) {
  const id = Crypto.randomUUID();
  const now = Date.now();

  const payload = { id, clientName, status: "in_progress", notes, created_at: now, updated_at: now };

  // Transacción segura: Guardar localmente y agregar a la cola
  db.withTransactionSync(() => {
    db.runSync(
      `INSERT INTO work_orders (id, client_name, status, notes, created_at, updated_at, sync_status) 
       VALUES (?, ?, ?, ?, ?, ?, 'pending')`,
      [id, clientName, "in_progress", notes, now, now]
    );

    db.runSync(
      `INSERT INTO sync_queue (table_name, record_id, action, payload, timestamp) 
       VALUES ('work_orders', ?, 'INSERT', ?, ?)`,
      [id, JSON.stringify(payload), now]
    );
  });

  return id;
}

Motor de Sincronización en Segundo Plano con @react-native-community/netinfo#

El servicio de sincronización escucha cambios en la conectividad del dispositivo y procesa la cola:

// src/services/syncEngine.ts
import NetInfo from "@react-native-community/netinfo";
import { db } from "@/lib/db";

let isSyncing = false;

export function startSyncListener() {
  NetInfo.addEventListener((state) => {
    if (state.isConnected && state.isInternetReachable) {
      processSyncQueue();
    }
  });
}

export async function processSyncQueue() {
  if (isSyncing) return;
  isSyncing = true;

  try {
    const queueItems: any[] = db.getAllSync(`SELECT * FROM sync_queue ORDER BY timestamp ASC`);

    for (const item of queueItems) {
      const payload = JSON.parse(item.payload);

      const response = await fetch("https://api.tudominio.com/api/sync", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          action: item.action,
          table: item.table_name,
          data: payload,
        }),
      });

      if (response.ok) {
        // Marcar como sincronizado y eliminar de la cola
        db.withTransactionSync(() => {
          db.runSync(`DELETE FROM sync_queue WHERE id = ?`, [item.id]);
          db.runSync(`UPDATE work_orders SET sync_status = 'synced' WHERE id = ?`, [item.record_id]);
        });
      }
    }
  } catch (error) {
    console.error("Error durante sincronización:", error);
  } finally {
    isSyncing = false;
  }
}

Beneficios para Operaciones Empresariales#

  1. Cero Latencia en la Interfaz: Las operaciones de lectura y guardado tardan menos de 5 milisegundos porque ocurren de forma local.
  2. Ahorro de Batería y Datos Móviles: La sincronización por lotes comprime y envía datos únicamente cuando es necesario.
  3. Continuidad Operativa Garantizada: Los trabajadores en terreno pueden registrar inventarios, firmas digitales y reportes en zonas sin cobertura sin temor a perder información.

¿Planeas Desarrollar una Aplicación Móvil Empresarial?#

Diseñar una aplicación con soporte offline robusto requiere experiencia en bases de datos embebidas, manejo de estado reactivo y protocolos de sincronización resilientes.

Si quieres crear una app móvil nativa para iOS y Android con React Native y Expo, contáctanos o conoce más sobre nuestros servicios de desarrollo móvil.

Etiquetas
React NativeExpoOffline-firstSQLiteApps MóvilesSincronización
Compartir:XLinkedInWhatsApp

¿Te gustaría profundizar en estos temas?

Aprende sobre desarrollo de software, apps a medida, automatizaciones con N8N, Next.js y Cloud con casos reales.

Hablemos