Home > Net >  Not able to get the id of the generated firebase document
Not able to get the id of the generated firebase document

Time:01-05

I'm trying to get the id of the generated firebase document, and I'm using addDoc to create a new doc.

I'm generating a new document on button click and that button calls the initializeCodeEditor function.

Anyone please help me with this!

Button Code:

import { useNavigate } from "react-router-dom"

import { useAuthContext } from "../../hooks/useAuthContext"
import { useFirestore } from "../../hooks/useFirestore"

import Button from "./Button"

const StartCodingButton = ({ document, setIsOpen }) => {
  const { user } = useAuthContext()
  const { addDocument, response } = useFirestore("solutions")
  const navigate = useNavigate()

  const initializeCodeEditor = async () => {
      await addDocument({
        ...document,
        author: user.name,
        userID: user.uid,
      })

      if (!response.error) {
        console.log(response.document) // null
        const id = response?.document?.id; // undefined
        navigate(`/solution/${id}`, { state: true })
      }
  }

  return (
    <Button
      className="font-medium"
      variant="primary"
      size="medium"
      onClick={initializeCodeEditor}
      loading={response.isPending}
    >
      Start coding online
    </Button>
  )
}

export default StartCodingButton

addDocument code

import { useReducer } from "react"
import {
  addDoc,
  collection,
  doc,
  Timestamp,
} from "firebase/firestore"

import { db } from "../firebase/config"
import { firestoreReducer } from "../reducers/firestoreReducer"

const initialState = {
  document: null,
  isPending: false,
  error: null,
  success: null,
}

export const useFirestore = (c) => {
  const [response, dispatch] = useReducer(firestoreReducer, initialState)

  // add a document
  const addDocument = async (doc) => {
    dispatch({ type: "IS_PENDING" })

    try {
      const createdAt = Timestamp.now()
      const addedDocument = await addDoc(collection(db, c), {
        ...doc,
        createdAt,
      })
      dispatch({ type: "ADDED_DOCUMENT", payload: addedDocument })
    } catch (error) {
      dispatch({ type: "ERROR", payload: error.message })
    }
  }

  return {
    addDocument,
    response,
  }
}

firestoreReducer

export const firestoreReducer = (state, action) => {
  switch (action.type) {
    case "IS_PENDING":
      return { isPending: true, document: null, success: false, error: null }
    case "ADDED_DOCUMENT":
      return { isPending: false, document: action.payload, success: true, error: null }
  }
  throw Error("Unknown action: "   action.type)
}

CodePudding user response:

I have recreated this issue and found out this is happening because the response object in the useFirestore hook is not being updated until the next render cycle.

In order to get the updated response object, you can use the useEffect hook to trigger an update to the component whenever the response object changes.

So I recommend you to call initializeCodeEditor and make your app wait until response object change I used useEffect here

const initializeCodeEditor = async () => {
      await addDocument({
        author: user.name,
        userID: user.uid,
      })
//skip following if block it's just for understanding
if (!response.error) {
        console.log(response.document) // will obviously be null here as at first it is set null
        const id = response?.document?.id; // will obviously be undefined
        navigate(`/solution/${id}`, { state: true })
      }
  }

  useEffect(() => {
    if (!response.error) {
      setId(response?.document?.id);
      console.log("From App.js useEffect: "   response?.document?.id); // getting the document id here too 
    }
  }, [response])

//and in firestoreReducer
case "ADDED_DOCUMENT":{
        console.log("from Reducer: "   action.payload.id); //getting the document id here
        return { isPending: false, document: action.payload, success: true, error: null }
      }

OR you can use callback also without introducing useEffect like this:

const initializeCodeEditor = async () => {
  await addDocument({
    author: user.name,
    userID: user.uid,
  }, (response) => {
    console.log("From App: "   response?.document?.id); //Will run as callback
    if (!response.error) {
      setId(response?.document?.id);
    }
  })
}

This way, the callback function will be called after the addDocument function has completed and the response object will have the updated document id.

  • Related