0

I have the following react component that creates a new document ref and then subscribes to it with the useFirestoreDocData hook.

This hook for some reason triggers an infinite rerender loop in the component.

Can anyone see what might cause the issue?

import * as React from 'react';
import { useFirestore, useFirestoreDocData, useUser } from 'reactfire';
import 'firebase/firestore';
import 'firebase/auth';
import { useEffect, useState } from 'react';
import { Link, useHistory } from 'react-router-dom';


interface ICreateGameProps {
}

interface IGameLobbyDoc {
    playerOne: string;
    playerTwo: string | null;
}

const CreateGame: React.FunctionComponent<ICreateGameProps> = (props) => {
    const user = useUser();
    const gameLobbyDocRef = useFirestore()
        .collection('GameLobbies')
        .doc()

    //This for some reason triggers an infinite loop
    const { status, data } = useFirestoreDocData<IGameLobbyDoc>(gameLobbyDocRef);

    const [newGameId, setNewGameId] = useState('')
    const history = useHistory();

    useEffect(() => {
        async function createGameLobby() {
            const gl: IGameLobbyDoc = {
                playerOne: user.data.uid,
                playerTwo:null
            }

            if (user.data.uid) {
                const glRef = await gameLobbyDocRef.set(gl)
                setNewGameId(gameLobbyDocRef.id)
            }
        }
            
        createGameLobby()

        return () => {
            gameLobbyDocRef.delete();
        }
    }, [])

    return <>
        <h2>Gameid : {newGameId}</h2>
        <p>Waiting for second player to join...</p>
        <Link to="/">Go Back</Link>
    </>
};

export default CreateGame;
1
  • So apparently the issues dissapears when I pass an id to the call to .doc() when I get the document reference. But this is not what I want. I want to create a document and listen for changes to this document Commented Jun 17, 2021 at 20:59

1 Answer 1

1

The problem is when you're calling doc() without arguments:

  • firestore creates new document ref each time with new auto-generated id.
  • you pass this reference to the useFirestoreDocData that is responsible for creating and observing this document.
  • useFirestoreDocData makes request to the server to inform about new draft document.
  • server responds to this request with ok-ish response (no id conflicts, db is accessible, etc...).
  • created observer updates status of the created document
  • that triggers rerender (since the document data has updated).
  • on new rerender .doc() creates new document ref
  • gives it to the useFirestoreDocData and...

I believe you've got the idea.

To break out of this unfortunate loop we should ensure the .doc() call happens only once on the first render and the ref created by the it doesn't change on each rerender. That's exactly what useRef is for:

   ...
    const gameLobbyDocRef = React.useRef(useFirestore()
        .collection('GameLobbies')
        .doc())

    const { status, data } = useFirestoreDocData<IGameLobbyDoc>(gameLobbyDocRef.current);
   ...
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.