Open
Description
Operating System
macOS Ventura
Environment (if applicable)
Google Chrome 131.0.6778.205 (Official Build)
Firebase SDK Version
10.11.0
Firebase SDK Product(s)
Firestore, Auth
Project Tooling
Default React app
Detailed Problem Description
Context
- The given code requests a new user token - with forceRefresh set to true - every 7 seconds.
- The code also sets a onSnapshot listener to a test document with
includeMetadataChanges
set to true
Expected behavior
- The
onSnapshot
listener should only run once when the data loads
Actual behavior
- The onSnapshot listener runs each time the new token is generated. The
snapshot.metadata.fromCache
property toggles between true and false each time the listener runs.
Further observation: Setting forceRefresh
to false
in getIdTokenResult
fixes the issue
Conclusion: It's not obvious why force refreshing the token changes the metadata on the snapshot causing the listener to rerun.
The behavior might be a bug. Hence I have filed this report.
If it's not a bug, I would like to know if there's a way to skip these unnecessary runs of the snapshot listener.
Steps and code to reproduce issue
import { initializeApp } from 'firebase/app';
import { getAuth } from 'firebase/auth';
import { collection, doc, getFirestore, initializeFirestore, onSnapshot, setLogLevel } from 'firebase/firestore';
import React from 'react';
import { createRoot } from 'react-dom/client';
const root = createRoot(
document.getElementById('root')
);
const firebaseConfig = {
...your config...
};
const firebaseApp = initializeApp(firebaseConfig);
initializeFirestore(firebaseApp, {});
const user = getAuth().currentUser; // initialize auth
setTimeout(() => {
onSnapshot(doc(collection(getFirestore(), 'test_collection'), 'test_document'), { includeMetadataChanges: true, }, (snapshot) => {
let data = null;
if (snapshot.exists()) {
data = snapshot.data();
}
console.log('users readonly data', data, snapshot.metadata);
}, undefined);
}, 1000);
setInterval(async () => {
console.log('token got', await getAuth().currentUser.getIdTokenResult(true));
}, 7_000);
function App() {
return <div>'Hello World'</div>;
}
root.render(<App />);