I’m new to React and Firestore (ver 9).
I’ve followed tutorials and created a simple listener that reads and displays a collection. I expected Firestore to open Websocket by default and keep docs in sync over it.
It turned out that instead, it is making a POST request several times per second to endpoint https://firestore.googleapis.com/google.firestore.v1.Firestore/Listen/channel?VER=8&database=...
I’m not in VPN and my firewall shouldn’t block websockets either.
Should I worry about such a huge number of requests?
Can I somehow force FS to use Websockets?
I read about Firebase.INTERNAL.forceWebSockets(); but it seems to be not accessible in Typescript.
My component:
export default function App() {
const dogsCol = collection(firestore, 'dogs');
const [dogs, setDogs] = React.useState<Dog[]>([]);
useEffect(() => {
const unSubscribe = onSnapshot(dogsCol, dogsSnap => {
const dogsArray = dogsSnap.docs.map(dogSnap => {
const dog = dogSnap.data() as Dog;
dog.id = dogSnap.id;
return dog;
});
setDogs(dogsArray);
});
return () => unSubscribe();
});
return (
<Container maxWidth="sm">
<Box sx={{ my: 4 }}>
{dogs.map(dog => <div key={dog.id}>{dog.name}</div>)}
</Box>
</Container>
);
}
My Firestore config:
const firebaseConfig = {
apiKey: "...",
// etc
};
const app = initializeApp(firebaseConfig);
export const auth = getAuth(app);
export const firestore = getFirestore(app);
const provider = new GoogleAuthProvider();
provider.setCustomParameters({
prompt: 'select_account'
});
export const signInWithGoogle = () => signInWithPopup(auth, provider)
>Solution :
Issue:
The reason your get the post request several times per second is because your useEffect hasn’t got any dependency array and
You can listen to a document with the onSnapshot() method. An initial call using the callback you provide creates a document snapshot immediately with the current contents of the single document. Then, each time the contents change, another call updates the document snapshot.
(the highlighted part is changing your dogs state, which is causing a re-render, which is calling the unsubscribe method, and after the re-render the useEffect is entered again and you get an infinite loop)
Adding an empty array should fix that issue (and yes, you should worry and avoid that since it can cause frontend and backend issues like performance , freezes, crashes, and also can get you some firestore bills to pay).
How to fix it:
Try changing your useEffect to
useEffect(() => {
const unSubscribe = onSnapshot(dogsCol, dogsSnap => {
const dogsArray = dogsSnap.docs.map(dogSnap => {
const dog = dogSnap.data() as Dog;
dog.id = dogSnap.id;
return dog;
});
setDogs(dogsArray);
});
return () => unSubscribe();
},[]); // <- this empty array will cause this to only execute the effect onMount
Adding the empty dependency array (and therefore subscribing only on component mount) should keep your data in sync if you set the rest of it right ( without the need of Firebase.INTERNAL.forceWebSockets(); or anything similar )