Firebase RTDB: one-time read vs real-time listener
Firebase Realtime Database gives you two ways to read data: once (get() / once())
or as a continuous listener (onValue() / on()).
Choosing wrong wastes reads and keeps WebSocket connections open for no reason.
SDK v9 (modular) — the modern way
import { getDatabase, ref, get } from 'firebase/database'; const db = getDatabase(); // ✅ Legge una volta sola — ideale per dati storici o config async function readOnce(path) { const snap = await get(ref(db, path)); if (snap.exists()) { return snap.val(); // oggetto JS con i dati } return null; } // Uso const utente = await readOnce(`users/${uid}`); console.log(utente.nome);
import { getDatabase, ref, onValue, off } from 'firebase/database'; const db = getDatabase(); // ✅ Ascolta le modifiche in real-time function listenMessages(chatId, callback) { const chatRef = ref(db, `chats/${chatId}/messages`); const unsub = onValue(chatRef, snap => { const msgs = snap.exists() ? Object.values(snap.val()) : []; callback(msgs); }); // Restituisce la funzione di unsubscribe — chiamala quando esci dalla pagina return unsub; } // Avvia ascolto const stopListening = listenMessages('room-42', msgs => { console.log('Nuovi messaggi:', msgs); }); // Ferma l'ascolto (es. quando l'utente lascia la pagina) // stopListening();
SDK v8 (compat) — if you're still on the old SDK
const db = firebase.database(); // Lettura una tantum (v8) db.ref(`users/${uid}`).once('value').then(snap => { if (snap.exists()) console.log(snap.val()); }); // Ascolto real-time (v8) const chatRef = db.ref(`chats/room-42/messages`); chatRef.on('value', snap => { console.log(snap.val()); }); // Rimuovi listener chatRef.off('value');
When to use which
| Use case | Method | Why |
|---|---|---|
| User profile on load | get() | Static data, doesn't change while user is logged in |
| App configuration | get() | Read once, store locally in memory |
| Real-time chat | onValue() | Messages arrive while the user is on the page |
| Online presence | onValue() | Changes frequently and unpredictably |
| Order history / logs | get() | Immutable past data — no reason to keep listening |
| Incoming notifications | onValue() | Must appear instantly without a page reload |
Rule of thumb: if the data can change while the user is on the page and they need to see it immediately, use onValue(). In all other cases use get() and save connections and costs.
Common memory leak: every onValue() opens a WebSocket connection that stays active until you call unsubscribe(). In a SPA, always clean up listeners when the component is unmounted.