0

React code

    import React, { useEffect, useState } from "react";
    import { getDocs, collection } from "firebase/firestore";
    import { auth, db } from "../firebase-config";
    import { useNavigate } from "react-router-dom";
    
    function Load() {
      const navigate = useNavigate();
    
      const [accountList, setAccountList] = useState([]);
      const [hasEmail, setHasEmail] = useState(false);
      const accountRef = collection(db, "accounts");

Am i using useEffect correctly?

      useEffect(() => {
        const getAccounts = async () => {
          const data = await getDocs(accountRef);
          setAccountList(
            data.docs.map((doc) => ({
              ...doc.data(),
              id: doc.id,
            }))
          );
        };
        getAccounts();
        emailCheck();
        direct();
      }, []);

checking whether email exists

      const emailCheck = () => {
        if (accountList.filter((e) => e.email === auth.currentUser.email)) {
          setHasEmail(true);
        } else {
          setHasEmail(false);
        }
      };

Redirecting based on current user

      const direct = () => {
        if (hasEmail) {
          navigate("/index");
        } else {
          navigate("/enterdetails");
        }
      };
      return <div></div>;
    }

The code compiles but doesn't redirect properly to any of the pages. What changes should I make? First question posted excuse me if format is wrong.

arw_29
  • 13
  • 4

1 Answers1

1

There are two problems here:

useEffect(() => {
  const getAccounts = async () => {
    const data = await getDocs(accountRef);
    setAccountList(
      data.docs.map((doc) => ({
        ...doc.data(),
        id: doc.id,
      }))
    );
  };
  getAccounts();
  emailCheck();
  direct();
}, []);

In order:

  1. Since getAccounts is asynchronous, you need to use await when calling it.
  2. But even then, setting state is an asynchronous operation too, so the account list won't be updated immediately after getAccounts completes - even when you use await when calling it.

If you don't use the accountList for rendering UI, you should probably get rid of it as a useState hook altogether, and just use regular JavaScript variables to pass the value around.

But even if you use it in the UI, you'll need to use different logic to check its results. For example, you could run the extra checks inside the getAccounts function and have them use the same results as a regular variable:

useEffect(() => {
  const getAccounts = async () => {
    const data = await getDocs(accountRef);
    const result = data.docs.map((doc) => ({
      ...doc.data(),
      id: doc.id,
    }));
    setAccountList(result);
    emailCheck(result);
    direct();
  };
  getAccounts();
}, []);

const emailCheck = (accounts) => {
  setHasEmail(accounts.some((e) => e.email === auth.currentUser.email));
};

Alternatively, you can use a second effect that depends on the accountList state variable to perform the check and redirect:

useEffect(() => {
  const getAccounts = async () => {
    const data = await getDocs(accountRef);
    setAccountList(
      data.docs.map((doc) => ({
        ...doc.data(),
        id: doc.id,
      }))
    );
  };
  getAccounts();
});
useEffect(() => {
  emailCheck();
  direct();
}, [accountList]);

Now the second effect will be triggered each time the accountList is updated in the state.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • Yeah, I tried the first solution but the following error occurs "Unexpected reserved word "await"". do async and await have to be used in pairs? – arw_29 Aug 13 '22 at 18:06
  • You can only use `await` in an `async` context indeed. I updated the first example in my answer. – Frank van Puffelen Aug 13 '22 at 18:12