Tu app funciona perfecto en tu casa y es inservible en el metro. Detectar la red, decidir qué hacer sin ella, y sincronizar cuando vuelve.
Etiquetas
El supuesto que traes de web
En el curso web nunca pensaste en la red. Y con razón: en una laptop conectada, la red es tan confiable que se puede dar por hecha. Un fallo de red es la excepción.
En móvil es al revés. Tu usuario entra al metro, al elevador, al sótano del edificio; se le acaban los datos a mitad de mes; se conecta al wifi del café que exige aceptar un portal. La conexión intermitente no es el caso raro: es el caso normal.
Por eso esta clase es la diferencia conceptual más grande entre las dos plataformas, y es donde tu app deja de parecer un ejercicio escolar.
Detectar no es tan simple como parece
NetInfo te da el estado de la red, pero con una distinción que casi todos ignoran:
isConnected— hay wifi o datos activos.isInternetReachable— además, internet responde de verdad.
No son lo mismo, y el caso que lo demuestra es cotidiano: te conectas al wifi de un café pero no has aceptado su portal de acceso. isConnected dice true y no hay internet. Si tu app solo revisa lo primero, cree que puede pedir datos y falla exactamente igual que sin señal — pero ahora sin avisarle al usuario, porque "sí hay red".
Las tres estrategias
Aquí está el corazón de la clase, y es una decisión de diseño, no de código. Cada acción de tu app cae en una de tres categorías:
| Estrategia | Cuándo | Qué le dices al usuario |
|---|---|---|
| Bloquear | La acción no tiene sentido sin servidor: pagar, iniciar sesión, ver un saldo real | Deshabilitas y explicas por qué |
| Degradar | Hay algo útil que mostrar aunque no esté fresco: listados ya vistos, detalles en caché | Muestras el contenido con aviso de su antigüedad |
| Encolar | La acción puede aplicarse después: marcar una tarea, enviar un mensaje, guardar una nota | Lo reflejas ya en pantalla, marcado como pendiente |
El error de diseño más común es tratar todo como "bloquear" (una app inútil sin señal) o todo como "encolar" (una app que promete cosas que no cumple). El trabajo es clasificar pantalla por pantalla, y eso es lo que te pide la práctica de hoy.
Leer sin red: la caché que ya sabes construir
La clase pasada guardaste la última respuesta de tu API. Hoy le das su verdadero uso: pinta la caché primero, pide datos después.
Ese orden cambia por completo la sensación de la app. Con red, el usuario ve contenido al instante en vez de un spinner. Sin red, ve los datos de ayer en vez de una pantalla vacía. La única condición es la honestidad: si lo que muestras puede estar viejo, dilo.
Escribir sin red: la cola
Cuando el usuario hace algo sin conexión, tienes dos opciones: perder su trabajo o guardar la intención para aplicarla después. La cola es simplemente una lista de acciones pendientes en AsyncStorage que se procesa al recuperar la señal.
Dos detalles que el tercer snippet resuelve y que suelen fallar:
- El orden importa — se recorre con
for...ofyawait, no conforEach(que no espera a nadie, como aprendiste en la Auditoría IA #2). - Las que fallan se conservan para el siguiente intento, en vez de descartarse en silencio.
Y el problema difícil que conviene que conozcas aunque no lo resuelvas hoy: los conflictos. Si el usuario editó algo sin red y alguien más lo editó en el servidor, ¿quién gana? La respuesta honesta para tu proyecto es "el último que sincroniza", y está bien — pero saber que el problema existe es lo que se espera de ti.
El principio que gobierna todo
El usuario siempre debe saber si lo que ve está fresco, y si lo que hizo ya salió del teléfono.
Una app que muestra datos viejos sin avisar, o que dice "¡Enviado!" cuando en realidad encoló algo, rompe la confianza del usuario de una forma que no se recupera. La conexión puede fallar — eso lo perdonan. Que la app mienta sobre ello, no.
En tu proyecto
Tu proyecto ahora exige comportamiento definido sin conexión. "Definido" no significa que todo funcione offline: significa que tú decidiste qué pasa en cada pantalla y el usuario recibe un mensaje digno.
Empieza por el diagnóstico de la práctica: activa el modo avión, usa tu app cinco minutos y anota todo lo que se rompe. Vas a encontrar más de lo que esperas — y esa lista es exactamente el guion de tu defensa.
Ejemplos de Código
4 ejemplos
Detectar el estado de la red
Y la distinción que casi todos pasan por alto.
1import { useNetInfo } from "@react-native-community/netinfo";
2
3function MiPantalla() {
4 const { isConnected, isInternetReachable, type } = useNetInfo();
5
6 // isConnected → hay wifi o datos ACTIVOS
7 // isInternetReachable → además, INTERNET responde de verdad
8 // type → "wifi" | "cellular" | "none" | ...
9}
10
11🚨 No son lo mismo. El caso clásico: el wifi del café al que te
12conectaste pero cuyo portal de acceso no has aceptado.
13isConnected = true, isInternetReachable = false.
14Si solo revisas isConnected, tu app cree que hay red y falla igual.
15
16Y ojo: isInternetReachable puede ser `null` mientras se determina.
17Trátalo como "aún no sé", no como "no hay".Las tres estrategias sin conexión
Toda acción de tu app cae en una de estas tres.
1BLOQUEAR — la acción no tiene sentido sin servidor
2 Ejemplos: pagar, iniciar sesión por primera vez, ver saldo real
3 UI: deshabilitar el botón + explicar por qué
4 Regla: nunca finjas que se hizo algo que no se hizo
5
6DEGRADAR — hay algo útil que mostrar, aunque no esté fresco
7 Ejemplos: listados ya vistos, detalle en caché, borradores
8 UI: mostrar contenido + avisar "datos del 12 de nov"
9 Regla: contenido viejo con aviso > pantalla vacía
10
11ENCOLAR — la acción puede esperar y aplicarse después
12 Ejemplos: marcar tarea, enviar mensaje, dar like, guardar nota
13 UI: reflejarlo YA en pantalla + marcar "pendiente de enviar"
14 Regla: el mensaje debe decir la verdad ("se enviará", no "enviado")Cola de acciones pendientes
Guardar la intención, aplicarla cuando vuelva la red.
1const COLA = "cola.pendientes";
2
3export async function encolar(accion) {
4 const cola = JSON.parse((await AsyncStorage.getItem(COLA)) || "[]");
5 cola.push({ ...accion, id: Date.now() });
6 await AsyncStorage.setItem(COLA, JSON.stringify(cola));
7}
8
9export async function sincronizar() {
10 const cola = JSON.parse((await AsyncStorage.getItem(COLA)) || "[]");
11 const fallidas = [];
12
13 for (const accion of cola) { // en orden: for...of, NO forEach
14 try {
15 await enviarAlServidor(accion);
16 } catch {
17 fallidas.push(accion); // se reintenta la próxima vez
18 }
19 }
20 await AsyncStorage.setItem(COLA, JSON.stringify(fallidas));
21}
22
23// Dispararla al recuperar conexión:
24useEffect(() => {
25 if (isConnected) sincronizar();
26}, [isConnected]);
27
28🚨 forEach con async NO espera (Auditoría IA #2 del curso web):
29la función terminaría antes de enviar nada.El indicador honesto
La UI debe decir la verdad sobre el estado de los datos.
1{!isConnected && (
2 <View style={styles.banner}>
3 <Text>Sin conexión — verás los últimos datos guardados</Text>
4 </View>
5)}
6
7{desdeCache && isConnected && (
8 <Text style={styles.aviso}>Actualizando…</Text>
9)}
10
11{pendientes > 0 && (
12 <Text style={styles.aviso}>
13 {pendientes} cambio(s) por enviar
14 </Text>
15)}
16
17Principio: el usuario SIEMPRE debe saber si lo que ve está fresco
18y si lo que hizo ya salió del teléfono. Una app que miente sobre
19eso pierde la confianza y no se recupera.Recursos
4 recursos disponibles
¡Hora de Practicar!
Práctica Guiada — Tu app en el metro
Definir e implementar el comportamiento sin conexión de tu proyecto.
Sobre tu proyecto integrador:
- Diagnostica primero. Activa el modo avión y usa tu app cinco minutos. Anota todo lo que ves: pantallas vacías, spinners eternos, errores crudos, botones que no responden.
- Clasifica cada pantalla en una de las tres estrategias: bloquear, degradar o encolar (ver la tabla de la clase).
- Implementa la detección de estado de red con
NetInfoy un indicador honesto en la UI. - Implementa la lectura offline de tu pantalla principal: si hay caché, se muestra; el indicador avisa que los datos pueden estar viejos.
- Implementa una acción encolada (o justifica por escrito por qué tu app no la necesita).
Entrega: el video o las capturas del antes/después en modo avión, más el commit correspondiente.
Desafío de Código
Ejercicios — Elige la estrategia
No todo se resuelve igual sin red. Clasificar es el trabajo.
Para cada acción, di si la estrategia correcta sin conexión es bloquear, degradar o encolar, y qué le muestras al usuario:
- Ver el listado de productos que ya cargó antes
- Enviar un mensaje en un chat
- Pagar una compra con tarjeta
- Marcar una tarea como completada
- Iniciar sesión por primera vez
- Ver el detalle de un producto que nunca abrió
- Subir la foto de perfil
- Consultar el saldo de una cuenta bancaria
Después responde: para las que elegiste encolar, ¿qué le dices al usuario para que no crea que ya quedó listo en el servidor?
Reto de Lectura
Reto de Lectura — La app que solo funciona en tu casa
Esta pantalla pasó todas las pruebas del salón y es inservible fuera. Cuatro supuestos sobre la red que no se sostienen en la calle.
Esta pantalla se probó en el laboratorio con wifi y funcionó perfecto. Diagnostica qué vive el usuario en el metro y encuentra los 4 supuestos rotos.
jsx1function PantallaPedidos() { 2 const [pedidos, setPedidos] = useState([]); 3 const [cargando, setCargando] = useState(true); 4 5 useEffect(() => { 6 fetch("https://api.miapp.com/pedidos") 7 .then((r) => r.json()) 8 .then((datos) => { 9 setPedidos(datos); 10 setCargando(false); 11 }); 12 }, []); 13 14 async function confirmarPedido(id) { 15 await fetch(`https://api.miapp.com/pedidos/${id}/confirmar`, { 16 method: "POST", 17 }); 18 alert("¡Pedido confirmado!"); 19 } 20 21 if (cargando) return <Spinner />; 22 23 return ( 24 <FlatList 25 data={pedidos} 26 keyExtractor={(p) => p.id} 27 renderItem={({ item }) => ( 28 <Pedido dato={item} onConfirmar={() => confirmarPedido(item.id)} /> 29 )} 30 /> 31 ); 32}
Preguntas:
- El usuario abre la pantalla sin señal. ¿Qué ve, exactamente, y por cuánto tiempo?
- El usuario ya había abierto esta pantalla ayer con wifi. ¿Por qué hoy no ve nada?
- El usuario toca "Confirmar" con señal intermitente. ¿Qué ve? ¿El pedido se confirmó o no?
- La señal vuelve a los dos minutos. ¿Qué hace la app?
- Propón la versión corregida (describe la estrategia; el código puede ser esquemático).
Documentación Oficial
Documentación de apoyo
APIs y lecturas para profundizar.
Clase 18 de 31 en la ruta Desarrollo movil