skip to Main Content

I have this program which renders ui after fetching data from firebase and is expected to rerender after every updates it get from database but i am getting the updates as expected and able to log the values but i am not able to update the value inside usestate. The ui gets render initially but no rerender after other updates.

my main isssue is that the ui is not rendering after initial render inspite of recieving updates

const [isLoaded, setIsLoaded] = useState(false);
  const [lobbyDetails, setLobbyDetails] = useState<LobbyDetails>({
    allowed_games: [],
    code: "",
    desc: "",
    game: "",
    host: "",
    maxPlayers: 0,
    minPlayers: 0,
    players: [],
    status: "",
  });

  useEffect(() => {
    // Listen for real-time changes in the data
    // Initialize Firebase app
    initializeApp(firebaseConfig);
    // Initialize database
    const db = getDatabase();
    // Reference to the specific location in the database
    const dbRef = ref(db, `lobbies/${lobbyId}`);
    onValue(dbRef, (snapshot) => {
      new Promise((resolve, reject) => {
        if (snapshot.exists()) {
          const data = snapshot.val();
          console.log("Data is available inside if");
          console.log(data);
          resolve(data);
        } else {
          console.log("No data available");
          reject(new Error("No data available"));
        }
      })
        .then((data) => {
          setIsLoaded(true);
          setLobbyDetails((prevDetails) => ({
            ...prevDetails,
            ...data,
          }));    // this is not working      
          console.log("Data is available inside then");
          console.log(lobbyDetails); // this is not working: log the initial value of lobbyDetails but not updated value
          console.log(data); // this is working: log the updated data every time database is updated
        })
        .catch((error) => {
          console.error(error);
        });
    });
  }, []);

help me!!

I am stuck

2

Answers


  1. This is React related, react useEffect triggers based on the deps argument

    // type: function useEffect(effect: EffectCallback, deps?: DependencyList): void
    useEffect(()=> {
      console.log("triggered on `deps` change")
    }, [deps])
    

    useEffect takes two arguments, one the function to run, and the other when to trigger that function (as an array). useEffect with no deps (empty array) as you are using will only be executed when the component is rendered. In order to get a console.log() each time the lobbyDetails are updated you must pass lobbyDetails as deps to the useEffect.

    // Use another useEffect to observe changes to lobbyDetails
    useEffect(() => {
      console.log("LobbyDetails updated:", lobbyDetails);
    }, [lobbyDetails]);
    
    Login or Signup to reply.
  2. The problem lies in the way you are trying to log the updated value of lobbyDetails immediately after calling setLobbyDetails. The state updates performed by setLobbyDetails are asynchronous, meaning that the updated value may not be immediately available right after calling setLobbyDetails. I have modified your code below;

    const [isLoaded, setIsLoaded] = useState(false);
    const [lobbyDetails, setLobbyDetails] = useState<LobbyDetails>({
      allowed_games: [],
      code: "",
      desc: "",
      game: "",
      host: "",
      maxPlayers: 0,
      minPlayers: 0,
      players: [],
      status: "",
    });
    
    useEffect(() => {
      initializeApp(firebaseConfig);
      const db = getDatabase();
      const dbRef = ref(db, `lobbies/${lobbyId}`);
      
      const onDataChange = (snapshot) => {
        if (snapshot.exists()) {
          const data = snapshot.val();
          console.log("Data is available inside onDataChange");
          console.log(data);
          setLobbyDetails((prevDetails) => ({
            ...prevDetails,
            ...data,
          }));
        } else {
          console.log("No data available");
        }
      };
      
      const onError = (error) => {
        console.error(error);
      };
      
      const dbRefSubscription = onValue(dbRef, onDataChange, onError);
      
      return () => {
        // Clean up the subscription when the component unmounts
        off(dbRef, onDataChange);
        // You might also want to handle the error case:
        // off(dbRef, onError);
      };
    }, [lobbyId]); // Include 'lobbyId' as a dependency
    
    useEffect(() => {
      console.log("Updated lobbyDetails");
      console.log(lobbyDetails);
    }, [lobbyDetails]); // Log lobbyDetails whenever it changes
    

    I also included [lobbyDetails] as a dependency for useEffect, it will run whenever lobbyDetails is updated. Hope this helps!

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search