13 minuti di lettura
Quando l’ufficio è online solo sulla carta
In una demo l’applicazione viene aperta su una rete stabile, con il Wi-Fi che funziona e l’API sempre raggiungibile. In un ufficio reale le cose sono meno ordinate.
Ci sono stanze in cui il segnale cade, reti aziendali che richiedono un nuovo accesso, hotspot congestionati, VPN che si interrompono e telefoni che passano dal Wi-Fi alla rete mobile proprio mentre l’utente sta inviando un’azione. A volte l’icona del Wi-Fi è presente, ma il server non risponde. Altre volte la rete funziona, ma è così lenta da rendere un tap apparentemente innocuo una richiesta bloccata per molti secondi.
Per un’app HR il problema è concreto. Una persona può dover consultare una comunicazione, aprire una richiesta ferie o completare un’attività legata alla giornata lavorativa. Se l’app reagisce soltanto con un generico errore di rete, l’utente non capisce se il problema dipende dal telefono, dall’ufficio o dal servizio.
Gestire l’offline non significa semplicemente mostrare la scritta «Nessuna connessione». Significa riconoscere lo stato reale del percorso e decidere che cosa l’app può fare senza inventare dati o conferme.
Offline totale e connessione debole non sono la stessa cosa
La prima distinzione da fare è tra due situazioni che spesso vengono trattate come se fossero identiche.
Offline totale
Il dispositivo non ha una rete attiva, oppure la rete non permette di raggiungere Internet. In questa condizione una nuova richiesta HTTP non può normalmente arrivare all’API.
Connessione debole o instabile
Il dispositivo risulta collegato, ma il servizio è lento, intermittente o irraggiungibile. La richiesta può impiegare molto tempo, fallire con un timeout oppure arrivare al server dopo che l’utente ha già premuto di nuovo il pulsante.
Questa differenza cambia l’esperienza da progettare. Nel primo caso possiamo mostrare subito una condizione offline. Nel secondo non possiamo promettere che «online» significhi «operazione completata»: serve uno stato di caricamento, un timeout ragionevole, un messaggio preciso e una strategia per evitare duplicati.
Un’app non dovrebbe dedurre la riuscita di un’operazione dalla sola presenza del Wi-Fi. L’unica conferma dell’azione arriva dalla risposta del servizio competente.
Che cosa rileva @react-native-community/netinfo
Nel progetto myGenius utilizziamo @react-native-community/netinfo per osservare lo stato della rete. La libreria espone due informazioni che è importante non confondere:
isConnected: indica se esiste una connessione di rete attiva;isInternetReachable: indica se Internet è raggiungibile attraverso quella connessione.
Entrambi i valori possono essere null mentre lo stato è ancora sconosciuto. Per questo una condizione troppo aggressiva come state.isConnected === false può non descrivere correttamente la fase iniziale del controllo.
Una sottoscrizione di base è semplice:
import NetInfo from '@react-native-community/netinfo';
const unsubscribe = NetInfo.addEventListener((state) => {
console.log('Tipo rete:', state.type);
console.log('Connesso:', state.isConnected);
console.log('Internet raggiungibile:', state.isInternetReachable);
});
// Quando il componente o il servizio non serve più:
unsubscribe();
Per una verifica puntuale si può chiamare NetInfo.fetch():
const state = await NetInfo.fetch();
const connected =
state.isConnected === true &&
state.isInternetReachable !== false;
Questa espressione considera utilizzabile una rete con isInternetReachable === null, purché isConnected sia vero. È una scelta prudente rispetto all’idea opposta di bloccare l’app finché ogni informazione non è stata valorizzata, ma non sostituisce il controllo delle richieste reali.
La libreria è un segnale di connettività, non un monitoraggio completo della salute del backend. Un DNS che non risolve, un certificato scaduto, un server in errore o un endpoint lento possono rendere inutile una rete che dal punto di vista del sistema operativo risulta connessa.
La strategia scelta in myGenius
Nel codice attuale l’app esegue una verifica iniziale attraverso checkConnectionOnStart, definita in src/services/networkService.js. La funzione chiama NetInfo.fetch(), aggiorna isOffline, verifica anche la versione remota e infine nasconde la splash screen.
Durante la vita dell’app, App.tsx registra inoltre un listener globale con NetInfo.addEventListener(). Quando la rete torna utilizzabile, il listener può chiudere la prima schermata; quando la connessione viene persa, lo stato isOffline porta alla schermata dedicata.
La scelta attuale è una schermata di blocco offline. È una soluzione comprensibile per un’app il cui contenuto principale arriva da una WebView e non è realmente disponibile senza rete. Non è però l’unica possibilità, né deve essere applicata a ogni funzionalità.
Prima di scegliere bisogna chiedersi che cosa può fare l’app senza server:
- se non può leggere nulla di utile, il blocco è onesto;
- se può mostrare dati già sincronizzati, si può offrire una modalità di sola lettura;
- se può raccogliere un’azione da inviare in seguito, serve una coda locale con stato esplicito;
- se l’azione richiede autorizzazione immediata, timestamp server o verifica del device, non va presentata come completata offline.
Il punto non è rendere l’app sempre utilizzabile a ogni costo. Il punto è non promettere una capacità che il sistema non può garantire.
Tre livelli di esperienza offline
Un’app aziendale beneficia di almeno tre stati UX, invece di un unico booleano isOffline.
Stato online
Il dispositivo ha una rete e le richieste recenti al servizio hanno risposto correttamente. L’utente può eseguire le operazioni previste, sempre rispettando gli errori del backend.
Stato offline
Non è possibile raggiungere la rete o il servizio. Le azioni che richiedono conferma remota vengono disabilitate, oppure vengono messe in coda soltanto se il prodotto prevede davvero questa possibilità.
Stato incerto o degradato
La rete appare disponibile, ma le richieste sono lente o falliscono. In questo caso non conviene sostituire l’intera schermata con un errore immediato. È più utile mantenere l’interfaccia, mostrare un indicatore non invasivo e spiegare il problema quando una specifica operazione non riesce.
La distinzione può essere modellata così:
const getConnectivityStatus = (state) => {
if (state.isConnected === false) return 'offline';
if (state.isConnected === null) return 'unknown';
if (state.isInternetReachable === false) return 'degraded';
return 'online';
};
È un esempio concettuale, non una verità universale. In alcuni prodotti isInternetReachable === null va trattato come unknown; in altri si preferisce lasciare attive le funzioni e attendere la prima risposta dell’API.
Schermata di blocco o fallback locale?
La decisione deve dipendere dal valore dei dati e dalla natura delle operazioni.
Quando il blocco è corretto
La schermata di blocco è ragionevole quando:
- l’app è principalmente un contenitore di dati remoti;
- non esiste una cache sufficientemente aggiornata;
- ogni azione deve essere verificata subito dal backend;
- mostrare dati vecchi potrebbe indurre decisioni sbagliate;
- il prodotto non ha definito una coda offline e il team non vuole crearne una improvvisata.
In myGenius la schermata offline con messaggio e immagine di assenza connessione è coerente con il fatto che il core applicativo, in questa fase, vive nella WebView e necessita di rete.
Il messaggio, però, dovrebbe aiutare davvero. Oltre a comunicare l’assenza di connessione, può indicare di controllare Wi-Fi o rete mobile e spiegare che l’app riprenderà quando il collegamento tornerà disponibile. Un pulsante «Riprova» può essere utile, purché non avvii richieste infinite senza feedback.
Quando il fallback è migliore
Un fallback di sola lettura è preferibile quando l’utente può consultare dati sincronizzati in modo sicuro. In quel caso ogni contenuto deve mostrare il momento dell’ultimo aggiornamento:
Dati aggiornati il 3 agosto alle 09:42.
Sei offline: le nuove modifiche non sono ancora disponibili.
Un dato vecchio senza indicazione temporale sembra un dato attuale. È una scelta UX pericolosa soprattutto per calendari, turni, saldi ferie e informazioni che cambiano rapidamente.
Quando la coda offline è possibile
Una coda locale può funzionare per azioni semplici e idempotenti, come una nota o una richiesta esplicitamente salvata come «da inviare». Ogni elemento deve avere un identificativo univoco, uno stato (pending, sending, sent, failed) e una politica per i conflitti.
Una timbratura o un evento che ha valore legale o organizzativo richiede più attenzione. Il telefono può registrare quando l’utente ha premuto il pulsante, ma il server deve distinguere tra tempo del device e tempo di ricezione. L’app non deve mostrare «presenza registrata» prima della conferma del servizio.
La UX non deve colpevolizzare l’utente
La connessione può cadere senza che l’utente abbia fatto nulla di sbagliato. I messaggi dovrebbero evitare formule vaghe o accusatorie come «Errore sconosciuto» e preferire indicazioni concrete:
- «Non riesco a raggiungere il servizio. Controlla la rete e riprova.»
- «La connessione è lenta. L’operazione non è ancora stata confermata.»
- «Sei offline. Puoi consultare i dati già sincronizzati, ma le modifiche verranno inviate quando torni online.»
È utile distinguere almeno tre momenti:
- rilevazione: il sistema ha notato un cambio di rete;
- azione: l’utente ha chiesto qualcosa che richiede il backend;
- ripristino: la rete è tornata, ma eventuali operazioni devono ancora essere verificate o sincronizzate.
Il ritorno online non significa automaticamente che tutto sia stato inviato. Se una richiesta è fallita, l’app deve indicare se è stata ritentata, se è stata completata o se richiede un’azione dell’utente.
Evitare i falsi positivi
Uno degli errori più comuni è trasformare un segnale di rete in una certezza applicativa.
const connected = state.isConnected && state.isInternetReachable !== false;
setIsOffline(!connected);
Una condizione simile è utile come filtro iniziale, ma non deve essere usata per segnare un’operazione come riuscita. La richiesta HTTP deve comunque gestire:
- timeout;
- codici HTTP di errore;
- risposta non valida;
- interruzione durante l’invio;
- ritentativi controllati;
- duplicazione dell’azione;
- sessione scaduta;
- rientro online durante una richiesta già in corso.
Un retry automatico senza idempotency key può creare due richieste identiche al server. Per un’azione che modifica dati, il backend dovrebbe poter riconoscere un identificativo già elaborato e restituire lo stesso risultato senza applicare due volte l’operazione.
Ritorno online e ciclo di vita dell’app
Il listener di NetInfo è utile, ma non è l’unico evento da osservare. Un’app può restare in background per minuti o ore e tornare in primo piano con uno stato di rete cambiato. React Native espone AppState proprio per sapere quando l’app passa da background ad active.
Una strategia ragionevole è:
- usare NetInfo per reagire ai cambi di connettività;
- usare AppState per eseguire un controllo quando l’app torna attiva;
- evitare di lanciare più sincronizzazioni contemporaneamente;
- aggiornare i dati dopo una conferma reale del servizio;
- rimuovere sempre listener e timer quando non servono più.
Un esempio semplificato:
useEffect(() => {
const unsubscribeNetInfo = NetInfo.addEventListener(setNetworkState);
const subscription = AppState.addEventListener('change', (nextState) => {
if (nextState === 'active') {
refreshConnectionAndData();
}
});
return () => {
unsubscribeNetInfo();
subscription.remove();
};
}, []);
Il metodo refreshConnectionAndData() deve essere protetto da un lock o da uno stato syncing, altrimenti una transizione di rete e una riapertura dell’app possono avviare due processi identici.
Sicurezza dei dati memorizzati offline
La modalità offline amplia il perimetro dei dati presenti sul telefono. Una cache locale non è un dettaglio neutro: può contenere nomi, presenze, richieste ferie, comunicazioni o informazioni sanitarie.
Prima di conservare dati offline bisogna decidere:
- quali informazioni sono davvero necessarie;
- per quanto tempo restano sul dispositivo;
- se devono essere cifrate;
- quando vengono cancellate dopo logout o revoca dell’account;
- cosa accade se il device è condiviso o compromesso;
- se le notifiche possono mostrare contenuti sensibili a schermo bloccato.
Non ha senso introdurre una cache offline per migliorare la UX e poi salvarla in un archivio non protetto. Allo stesso modo, un token scaduto o revocato non deve continuare ad autorizzare contenuti locali senza una policy chiara.
La modalità offline dovrebbe essere esplicita anche nel modello di autorizzazione. Vedere l’ultima copia di un dato non significa avere ancora il diritto di vedere ogni aggiornamento futuro.
Errori frequenti nella progettazione
Controllare solo isConnected
Essere collegati a un router non equivale a raggiungere Internet o l’API. È utile considerare anche isInternetReachable e, soprattutto, la risposta del backend.
Usare un solo booleano per tutto
isOffline è facile da leggere, ma non distingue stato sconosciuto, rete debole, richiesta in corso e servizio non disponibile. Anche se l’app mantiene un booleano per la UI principale, la logica delle singole operazioni deve avere stati più precisi.
Bloccare al primo evento incerto
All’avvio alcuni valori possono essere ancora null. Mostrare subito una schermata di errore può produrre un lampeggio o un blocco ingiustificato. Una fase iniziale di caricamento evita di trasformare l’incertezza temporanea in un errore visibile.
Ritentare senza controllo
Il retry deve avere un limite, un intervallo crescente e una condizione di arresto. Per le mutazioni serve anche idempotenza.
Nascondere l’errore dopo il ritorno online
La rete è tornata, ma una richiesta precedente potrebbe essere rimasta fallita. Il ripristino della connettività non cancella la storia dell’operazione.
Aggiungere una modalità offline senza un piano dati
La cache e la coda non sono un semplice AsyncStorage.setItem(). Richiedono scadenze, cifratura, conflitti, revoca e test. Se il prodotto non ne ha bisogno, una schermata offline onesta è spesso più sicura.
Una checklist pratica per un’app aziendale
Prima del rilascio, verifichiamo almeno questi casi:
- avvio senza Wi-Fi e senza rete mobile;
- avvio con rete presente ma Internet non raggiungibile;
- passaggio da Wi-Fi a rete mobile;
- perdita della rete durante un login;
- perdita della rete durante una modifica;
- rete molto lenta e timeout;
- ritorno online mentre l’app è in foreground;
- ritorno online dopo un periodo in background;
- doppio tap sul pulsante durante una richiesta lenta;
- logout mentre esistono dati locali;
- token scaduto mentre il device è offline;
- reinstallazione dell’app;
- dati vecchi mostrati in modalità di sola lettura;
- sincronizzazione interrotta a metà;
- server disponibile ma endpoint in errore.
Per ogni scenario deve essere chiaro cosa vede l’utente, cosa rimane sul device e quale conferma è stata realmente ricevuta dal backend.
Conclusione
La gestione offline è una decisione di prodotto prima ancora che una scelta di libreria. @react-native-community/netinfo fornisce segnali utili e un modo uniforme per osservare la rete, ma non decide se l’app possa considerare completata un’operazione.
In un’app aziendale la soluzione più affidabile è spesso ibrida: bloccare le funzioni che hanno bisogno di verifica immediata, mostrare dati locali soltanto quando sono datati e identificabili, e mettere in coda un’azione solo quando il prodotto è stato progettato per farlo davvero.
La regola più importante resta semplice: meglio dire chiaramente «non posso confermare questa operazione» che mostrare un’interfaccia fluida costruita su una certezza inesistente.
Domande frequenti
isConnected: true significa che l’app è online?
No. Indica una connessione di rete attiva, ma Internet o il backend potrebbero non essere raggiungibili. È utile osservare anche isInternetReachable e gestire la risposta reale delle richieste.
Posso usare NetInfo per capire se il server è disponibile?
NetInfo aiuta a capire la connettività del dispositivo. Non sostituisce un controllo applicativo sul backend, che può essere irraggiungibile, lento o in errore anche quando il telefono è connesso.
Devo bloccare sempre l’app quando manca la rete?
No. Dipende dai dati e dalle operazioni. Se l’app ha una cache sicura e datata può offrire sola lettura; se deve confermare ogni azione online, il blocco è più trasparente.
Posso salvare una richiesta ferie offline?
È possibile soltanto se il prodotto definisce una coda, una policy di conflitto, un identificativo idempotente e una conferma successiva del server. Fino a quel momento l’interfaccia dovrebbe parlare di richiesta «da inviare», non «approvata» o «registrata».




