0

I can log the data by clicking the button on the browser's console but the session data doesn't get rendered to the component. and I have added console logs inside the return statement to check whether if the state resets it seems not. and when the snapshot is received it adds the session to previous sessions rather than adding only new ones

const AssignedInterviews = () => {
    const [sessions, setSessions] = useState([]);
    const [loading, setLoading] = useState(true);
    const { user } = useAuth();

    const getSessionData = async (sessionRef) => {
        const session = await sessionRef.data();

        const panelRef = await db.collection("panels").doc(session.panel_id).get();
        const panel = await panelRef.data();

        const companyRef = await db
            .collection("companies")
            .doc(panel.company_id)
            .get();
        const company = await companyRef.data();

        const interviews = await db
            .collection("interviews")
            .where("session_id", "==", sessionRef.id)
            .get();

        const panel_no = panel.panel_no;
        const company_name = company.name;
        const company_logo = company.photoUrl;
        const interview_schedule = session.start_time;

        return {
            id: sessionRef.id,
            panel_no,
            company_name,
            company_logo,
            queue_length: interviews.size,
            interview_schedule,
        };
    };

    const fetchSessions = () => {
        try {
            db.collection("sessions")
                .where("assigned_students", "array-contains", user.uuid)
                .orderBy("start_time")
                .onSnapshot((snapshot) => {
                    console.log("Snaphot Recieved");
                    setLoading(true);
                    const new_sessions = [];
                    snapshot.forEach((sessionRef) => {
                        getSessionData(sessionRef)
                            .then((new_session) => {
                                new_sessions.push(new_session);
                            })
                            .catch((e) => {
                                console.log(e);
                            });
                    });
                    setLoading(false);
                    setSessions(new_sessions);
                });
        } catch (error) {
            console.log(error);
        }
    };

    useEffect(() => {
        fetchSessions();
    }, []);

    return (
        <Flex
            flexDirection='column'
            mt={5}
            width='100%'
            p={2}
            overflow='scroll'
            maxHeight={500}>
            <Heading size='md' mb={5}>
                Your Assigned Interviews
            </Heading>
            {!loading ? (
                sessions.map((session) => {
                    return <InterviewCard key={session.id} data={session} />;
                })
            ) : (
                <Center>
                    <Spinner />
                </Center>
            )}
            <Button
                onClick={() => {
                    console.log(sessions);
                }}>
                {JSON.stringify(sessions)}
            </Button>
        </Flex>
    );
};
  • Does this answer your question? [How to return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-asynchronous-call) – Emile Bergeron Jun 28 '21 at 02:28
  • Specifically, `new_sessions.push(new_session);` happens after `setSessions(new_sessions);` since `getSessionData(sessionRef)` returns a promise (asynchronous completion). – Emile Bergeron Jun 28 '21 at 02:30
  • It also might look like it works when logging after a button click, but that's only because the current sessions array gets mutated when the previous asynchronous tasks succeeds. Note that [it's an anti-pattern in React to mutate the state directly](https://stackoverflow.com/q/37755997/1218980), though fixing the initial problem should fix the state mutation anti-pattern at the same time. – Emile Bergeron Jun 28 '21 at 02:35

1 Answers1

-1

Added some changes:

  1. Made fetchSessions method async.
  2. Changed implementation of calling getSessionData. (currently this is sequential, although I can change it to run in parallel)
  3. Changes in error handling. (The outer try catch is sufficient)
  4. Added finally.

New implementation:

const fetchSessions = async () => {
  try {
    db.collection("sessions")
      .where("assigned_students", "array-contains", user.uuid)
      .orderBy("start_time")
      .onSnapshot((snapshot) => {
        console.log("Snaphot Recieved");
        setLoading(true);
        const new_sessions = [];
        snapshot.forEach((sessionRef) => {
          const newSession = getSessionData(sessionRef);
          new_sessions.push(newSession);
        });
        setSessions(new_sessions);
      });
  } catch (e) {
    console.log(e.message);
  } finally {
    setLoading(false);
  }
};
Shravan Dhar
  • 1,455
  • 10
  • 18