Red Baron
Red Baron

Reputation: 7642

How to wait for a successful async action before changing url?

so I'm using a popup to log my users in with firebase:

const loginToApp = (provider) => {
    firebaseApp
        .auth()
        .signInWithPopup(provider)
        .then(async (result) => {
            if (result.additionalUserInfo.isNewUser) {
                // problem is this line
                await setNewUserInformation(result.user.uid)
            }
            const { user } = result
            setUser(user)
            // and this line
            window.location.href = 'newRoute'
        })
        .catch((error) => {
            console.log('ERROR:', error)
        })
}

so if I remove window.location.href = 'visited' this all works fine and it sets in firebase. I'm probably doing something stupid but I cant figure out how to wait for this function to fire setNewUserInformation and to complete before I move to the new page?

function code:

export const setNewUserInformation = (userId) => {
    return {
        type: 'SET_NEW_USER_INFORMATION',
        userId,
    }
}

this then has a redux observable epic listening to it:

return action$.pipe(
    ofType('SET_NEW_USER_INFORMATION'),
    mergeMap((action) => {
        return from(
            firebaseApp.database().ref(firebaseRef).update(userInformation),
        ).pipe(
            mergeMap(() => {
                return [updatedUserInformationSuccess()]
            }),
            catchError((error) => of(updatedUserInformationFailure(error))),
        )
    }),
)

Upvotes: 2

Views: 1129

Answers (4)

artfulbeest
artfulbeest

Reputation: 1483

setNewUserInformation() is an action creator, which is sync. You do not need to wait for it as it does not return anything useful to you logic. What you need to do, is move window.location.href = 'newRoute' to separate logic, and make it depend on state returned from action creators updatedUserInformationSuccess() and updatedUserInformationFailure(error). If your component is functional, put this logic in a useEffect. If it is a class component, use ComponentDidUpdate lifecycle method.

Upvotes: 1

Mohit Gahlot
Mohit Gahlot

Reputation: 66

Are you using React? If yes, then you can simply use didUpdate Cycle to route to new url after successful action dispatched. Move your "window.location.href = 'newRoute'" under the ComponentDidUpdate with props check.

Upvotes: 0

Nhan Hoang
Nhan Hoang

Reputation: 147

Because on then You can returned a Promise and resolve later. We could re-write the code above like this below:

const loginToApp = (provider) => {
    firebaseApp
        .auth()
        .signInWithPopup(provider)
        .then((result) => {
            if (result.additionalUserInfo.isNewUser) {
                // return for next resolve function
                return setNewUserInformation(result.user.uid).then(() => result); 

            }
            return result;
        })
        .then((result) => {
            // after all above promises resolve
            const { user } = result
            setUser(user)
            // and this line
            window.location.href = 'newRoute'
        })
        .catch((error) => {
            console.log('ERROR:', error)
        })
}

Upvotes: 0

Anku Singh
Anku Singh

Reputation: 954

Use it like below

const loginToApp = (provider) => {
firebaseApp
    .auth()
    .signInWithPopup(provider)
    .then(async (result) => {
        new Promise((resolve, reject) => {
             if (result.additionalUserInfo.isNewUser) {
                // problem is this line
                setNewUserInformation(result.user.uid)
            }
           const { user } = result
           resolve(user)
        }).then((user)=>{
          setUser(user)
          // and this line
          window.location.href = 'newRoute'
        })
       
    })
    .catch((error) => {
        console.log('ERROR:', error)
    })
  }

Upvotes: 0

Related Questions