Home > database >  Data from firestore it's being fetched multiple times when login and logout (vanilla JS)
Data from firestore it's being fetched multiple times when login and logout (vanilla JS)

Time:11-29

Well I made this Library app, where an user can login and add books. So, when a user login the app fetch data from a firestore collection, cool. The problem exists when the user login once, logout and then login again without refreshing the app. If the user do this twice, the fetch twice, if thrice, the fetch thrice. The code that executes multiple times its the fetchBooks(), the signInWithGoogle() only executes once. Here's the code involved:


function signInWithGoogle(){
    const provider = new firebase.auth.GoogleAuthProvider()
        auth.signInWithPopup(provider)
            .then(result => {
                // Create the new user document in firestore
                createNewUserDocument(result.user)
                // fetch feed data
                auth.onAuthStateChanged(user =>{
                    user? fetchBooks() : null
                })
            }).catch(err => {
                console.log(err)
            })
        signUpForm.reset()
        signUpModal.hide()
        signInForm.reset()
        signInModal.hide()
}


function fetchBooks() {
    const docRef = db.collection('users').doc(auth.currentUser.uid).collection('books')
    docRef.get().then(querySnapshot =>{
        console.log(querySnapshot)
        querySnapshot.forEach(doc => {
            const data = doc.data()
            console.log(doc.data());
            addCardToHTML(data.title, data.author, data.pages, data.description, data.read)
        })
    })
}

CodePudding user response:

onAuthStateChanged is a subscription that triggers itself when there's a change in the user's authentication state.

So it will trigger when you log in, when you log out, etc.

So ideally you'd want to wait until the user logs in, and then call the fetchBooks() function, but if you keep doing it inside of the subscriber the function will trigger any time the subscriber emits a new value.

CodePudding user response:

I would recommend starting with a restructure of your code to have functions that do individual things. Right now, you have a function signInWithGoogle. That function should only sign the user in with Google and return a promise with the result of that sign in. Instead, you have it signing in the user, fetching books (which itself is also fetching books AND modifying the DOM), and calling methods on your signUp elements.

Restructuring this to have some other top-level function would likely help you handle your problem easier. Specifically, try something like this:

function handleSignIn() {
    signInWithGoogle()
        .then(fetchBooks)
        .then(books => {
            books.forEach(book => addCardToHTML(...))
        })
}

This is a good start because now it's clear what each individual function is doing. So now to handle your specific issue, I'll assume that the problem you're facing is that you're seeing the books be added multiple times. In that case, I would think what you'd want to happen is that:

  1. When a user is signed in, you want to load their books and display them on the page.
  2. When they log out, you want the books to be unloaded from the screen
  3. When they log back in, the books are re-loaded and displayed.

If all of those assumptions are correct, then your problem wouldn't be with the code you have, but rather the signout functionality. When the user signs out, you need to add a function that will remove the books from the HTML. That way, when they sign back in after signing out, the handleSignIn function will kick off again and the addCardToHTML function will be running on a blank HTML page rather than a page that already has the cards.

Example:

function handleSignOut() {
    signOut()
        .then(clearBookCards)
}

function clearBookCards() {
    // Manipulate DOM to remove all of the card HTML nodes
}
  • Related