Codex
Codex

Reputation: 1281

Firebase read with react useeffect async not waiting for document read

I have below code snippet in my auth context where I set login details along wit user specific details in context. But the problem is code exiting the useEffect block even though I used async for document read to complete. But code is going past useEffect anyway and user details are retrieved after that.

I would like to read the document before control goes out of useEffect.

Please let me know what I am doing wrong.

    useEffect(() => {
        auth.onAuthStateChanged(user => {
            let userDetails : IUser = {
                landingPage: "error",
                permissions: {
                    'none' : {
                        'read' : false,
                        'write' : false
                    }
                },
                role: "none",
                shopId: "none"
            };
            if (user) {
                console.log("Read user data now");
                (async function some() {
                    await readDocument("users", user.uid,function (result: IUser) {
                        userDetails = result;
                        console.log("Result received in ", result);
                    });
                })();
            }
            return setState({
                ...authInitialState,
                isAuthenticated: !!user,
                isInitialized: true,
                permissions: userDetails.permissions,
                user: user,
                landingPage: userDetails.landingPage
            });
        });
    }, []);

readdocument function

function readDocument(collection: string, docId: string, callback: any) {
    console.log("Going to read:", docId);
    db.collection(collection).doc(docId)
        .get()
        .then(function (doc) {
            callback(doc.data());
            console.log("Read data", doc.id, " => ", doc.data());
        })
        .catch(function (error) {
            console.log("Failed to write", error);
        });
}

Upvotes: 0

Views: 338

Answers (2)

Codex
Codex

Reputation: 1281

I tried something like this and it worked. Still not 100% sure what is the difference.

const onChange = (user) => {
        console.log("State changed");
        let userDetails: IUser = {
            landingPage: "error",
            permissions: {
                'none': {
                    'read': false,
                    'write': false
                }
            },
            role: "none",
            shopId: "none"
        };

        if (user) {
            getDocument("users", user.uid)
                .then(function (result) {
                    userDetails = result.data();
                    setState({
                        ...authInitialState,
                        isAuthenticated: !!user,
                        isInitialized: true,
                        permissions: userDetails.permissions,
                        user: user,
                        landingPage: userDetails.landingPage
                    });
                });
        }
    }

useEffect(() => {
        auth.onAuthStateChanged((user) => onChange(user));
    }, []);

Upvotes: 0

ssdev
ssdev

Reputation: 111

In order for readDocument to work with await it needs to be a promise that gets resolved. https://itnext.io/javascript-promises-and-async-await-as-fast-as-possible-d7c8c8ff0abc - scroll down to section async/await

Something like this (unverified) -

const readDocument = function (collection: string, docId: string, callback: any) {
  return new Promise((resolve, reject) => {
    db.collection(collection).doc(docId)
        .get()
        .then(function (doc) {
            resolve(doc.data());
            console.log("Read data", doc.id, " => ", doc.data());
        })
        .catch(function (error) {
            console.log("Failed to write", error);
            reject(error);
        });
  });
};

Upvotes: 2

Related Questions