Lección 13 de 20 · Lectura y práctica
Almacenamiento local con AsyncStorage y SQLite
Tipo de lección: VideoConcepto claveEl almacenamiento local es como la memoria de corto plazo de tu aplicacion movil. Mientras que las APIs externas son como consultar una biblioteca remota, el almacenamiento local es tu cuaderno.
Del concepto a la práctica
Taller de esta lección
Elige almacenamiento según la forma de consulta. Preferencias como modo: 'oscuro' caben en un valor serializado; pedidos con id, fecha, líneas y estado se benefician de registros consultables. En ambos casos define una clave o esquema y trata la lectura ausente como estado inicial, no como corrupción automática.
Ejemplo resuelto
AsyncStorage puede guardar cart:v1 con [{"id":"p1","qty":2}]. Al leer, parsea JSON y valida que cada elemento tenga id y cantidad positiva. Para tres pedidos filtrados por estado, SQLite permite preguntar por status = 'pending' sin cargar todo.
Pruébalo
Define la versión de la clave.
Guarda datos serializados.
Lee y valida la forma.
Usa una consulta acotada para registros estructurados.
Error frecuente: guardar objetos directamente donde se espera texto. Corrige usando serialización y captura de errores de parseo.
Ejercicio: persiste p1 con cantidad 2 y recupera.
Comprueba tu resultado
mismo id y cantidad; si la clave no existe, el carrito recuperado es [], no undefined.
JSON válido, hidratación y SQL actual
El valor serializado correcto es [{"id":"p1","qty":2}], con comillas dobles. Instala e importa AsyncStorage desde @react-native-async-storage/async-storage, no desde react-native. getItem('cart:v1') puede devolver null; en ese caso inicia []. Para contenido presente usa JSON.parse y verifica array, IDs strings únicos, qty entero positivo y productos conocidos. Un registro corrupto debe mostrar error/recuperación explícita, no declararse restaurado.
function leerCarrito(texto){
if(texto===null) return [];
const filas=JSON.parse(texto);
if(!Array.isArray(filas)||filas.some(f=>!f||!['p1','p2','p3'].includes(f.id)||!Number.isInteger(f.qty)||f.qty<=0))
throw new Error('Carrito inválido');
if(new Set(filas.map(f=>f.id)).size!==filas.length) throw new Error('IDs repetidos');
return filas;
}Termina hidratación antes de permitir al efecto guardar un carrito vacío. Guarda con setItem(clave,JSON.stringify(filas)) y trata errores de lectura/escritura. AsyncStorage no cifra: usa un almacén apropiado para secretos. No enseñes límites fijos2/6/10MB como universales de plataforma. SQLite actual usa openDatabaseAsync, execAsync para esquema fijo, runAsync para parámetros y getAllAsync para consultas; el viejo openDatabase/transacción no es intercambiable. Fixture pedidos o1=pending,o2=paid,o3=pending; WHERE status=? con parámetro pending devuelve o1/o3 si ordenas por id. AsyncStorage, SQLite.

Mapa de prácticaDistingue preferencias simples de datos estructurados que requieren consultas. AsyncStorage y SQLite no son un almacén adecuado para secretos en texto claro; usa las capacidades seguras de la plataforma y define sincronización y borrado.
Ver la infografía en tamaño completo ↗Tipo de lección: Video
Concepto clave
El almacenamiento local es como la memoria de corto plazo de tu aplicacion movil. Mientras que las APIs externas son como consultar una biblioteca remota, el almacenamiento local es tu cuaderno de notas personal donde guardas informacion que necesitas acceder rapidamente, incluso sin conexion a internet.
En React Native con Expo, tenemos dos opciones principales: AsyncStorage y SQLite. AsyncStorage es como una caja simple donde guardas cosas con etiquetas - perfecta para datos pequenos como preferencias de usuario o tokens. SQLite es como un archivador organizado con carpetas y documentos - ideal para datos estructurados complejos que necesitan consultas avanzadas.
La decision entre uno y otro depende del volumen y complejidad de tus datos. Para menos de 2MB y datos simples, AsyncStorage es suficiente. Para mas datos o relaciones complejas, SQLite es tu mejor opcion.
Como funciona en la practica
Vamos a implementar un sistema de almacenamiento para una app de tareas. Primero, instalaremos las dependencias necesarias. Para AsyncStorage, ya viene incluido en React Native, pero con Expo necesitamos instalar una version especifica.
Paso 1: Instalar dependencias. Abre tu terminal y ejecuta:
npx expo install @react-native-async-storage/async-storage
expo install expo-sqlitePaso 2: Configurar AsyncStorage para guardar el tema de la app (claro/oscuro). Paso 3: Configurar SQLite para guardar las tareas con fecha, prioridad y estado. Paso 4: Implementar sincronizacion entre almacenamiento local y servidor cuando haya conexion.
Codigo en accion
Veamos primero como usar AsyncStorage para guardar preferencias del usuario:
import AsyncStorage from '@react-native-async-storage/async-storage';
// Guardar un valor
const saveUserPreference = async (key, value) => {
try {
await AsyncStorage.setItem(key, JSON.stringify(value));
console.log('Preferencia guardada correctamente');
} catch (error) {
console.error('Error al guardar:', error);
}
};
// Ejemplo de uso
await saveUserPreference('@theme', 'dark');
await saveUserPreference('@notifications', true);
// Leer un valor
const getUserPreference = async (key) => {
try {
const value = await AsyncStorage.getItem(key);
return value != null ? JSON.parse(value) : null;
} catch (error) {
console.error('Error al leer:', error);
return null;
}
};
// Ejemplo de lectura
const theme = await getUserPreference('@theme');
console.log('Tema actual:', theme);Ahora, veamos SQLite para datos mas complejos. Antes teniamos solo AsyncStorage, pero al crecer la app necesitamos mas estructura:
import * as SQLite from 'expo-sqlite';
// Abrir o crear base de datos
const db = SQLite.openDatabase('tasks.db');
// Inicializar tabla
const initDatabase = () => {
db.transaction(tx => {
tx.executeSql(
'CREATE TABLE IF NOT EXISTS tasks (id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, completed BOOLEAN, priority INTEGER, created_at DATETIME DEFAULT CURRENT_TIMESTAMP)',
[],
() => console.log('Tabla creada/existe'),
(_, error) => console.error('Error creando tabla:', error)
);
});
};
// Insertar una tarea
const addTask = (title, priority = 1) => {
return new Promise((resolve, reject) => {
db.transaction(tx => {
tx.executeSql(
'INSERT INTO tasks (title, completed, priority) VALUES (?, ?, ?)',
[title, false, priority],
(_, result) => resolve(result.insertId),
(_, error) => reject(error)
);
});
});
};
// Consultar tareas pendientes
const getPendingTasks = () => {
return new Promise((resolve, reject) => {
db.transaction(tx => {
tx.executeSql(
'SELECT * FROM tasks WHERE completed = ? ORDER BY priority DESC, created_at ASC',
[false],
(_, { rows }) => resolve(rows._array),
(_, error) => reject(error)
);
});
});
};
// Ejemplo de uso
await initDatabase();
const taskId = await addTask('Comprar leche', 2);
const pendingTasks = await getPendingTasks();
console.log('Tareas pendientes:', pendingTasks);Errores comunes
1. No manejar errores en operaciones asincronas: Siempre usa try-catch con AsyncStorage y callbacks de error con SQLite. Sin esto, tu app puede crashear silenciosamente.
2. Exceder el limite de AsyncStorage: AsyncStorage tiene limite de ~6MB en iOS y ~10MB en Android. Si necesitas mas, migra a SQLite antes de que los usuarios tengan problemas.
3. No serializar datos complejos: AsyncStorage solo guarda strings. Si intentas guardar objetos directamente, se convertiran a [object Object]. Usa JSON.stringify() y JSON.parse().
4. Bloques de transaccion muy grandes en SQLite: Agrupa operaciones relacionadas en una sola transaccion, pero no metas todo en una. Divide en transacciones logicas.
5. Olvidar cerrar conexiones de base de datos: Con SQLite, aunque Expo maneja algunas cosas, en apps complejas considera cerrar conexiones cuando no las uses.
Checklist de dominio
- Puedo instalar y configurar tanto AsyncStorage como SQLite en un proyecto Expo
- Se cuando usar AsyncStorage (datos simples) vs SQLite (datos complejos)
- Implemento manejo de errores robusto en todas las operaciones de almacenamiento
- Serializo y deserializo datos correctamente para AsyncStorage
- Creo tablas y ejecuto consultas SQL basicas en SQLite
- Manejo transacciones apropiadamente para mantener integridad de datos
- Implemento una estrategia de sincronizacion entre almacenamiento local y servidor remoto
Implementa un sistema de notas con almacenamiento local
Crea una app de notas que permita:
- Crear nuevas notas con titulo y contenido
- Listar todas las notas ordenadas por fecha de creacion
- Marcar notas como favoritas
- Buscar notas por texto en titulo o contenido
- Persistir los datos localmente
Paso 1: Configura un nuevo proyecto Expo o usa uno existente
Paso 2: Instala las dependencias necesarias para AsyncStorage y SQLite
Paso 3: Decide que sistema usar (AsyncStorage o SQLite) basado en los requisitos
Paso 4: Implementa las funciones CRUD para las notas
Paso 5: Crea una interfaz basica con React Native para probar la funcionalidad
Paso 6: Agrega la funcionalidad de busqueda
Paso 7: Implementa la marcacion de favoritos
Paso 8: Prueba que los datos persistan al cerrar y reabrir la app
Pistas
- Considera usar SQLite por la necesidad de busqueda y ordenacion
- Para la busqueda, usa la clausula LIKE de SQL o filtra arrays en JavaScript
- Guarda las fechas como timestamps para facilitar el ordenamiento
Evalua tu comprension
Completa el quiz interactivo de arriba para ganar XP.
Sigue con React Native y Expo: Interfaces, Estado y APIs de Dispositivo
Esta lección forma parte de un curso de Cursalo. Revisa su programa y elige entre la compra individual o el acceso a toda la escuela.
Si ya tenías acceso a este curso, entra con tu cuenta: tus derechos y tu progreso se conservan. No necesitas comprarlo de nuevo.