Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Firestore client in React app doesn't use Websockets, instead makes hundreds POST requests

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.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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 )

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading