Apparently, the problem is due to the ui.delete() command being not fast enough.
Notice below that the "delete" is resolved after a new instance's constructor was fired already.

My code
import React from 'react'
import firebase from 'firebase'
import firebaseui from 'firebaseui'
import { Redirect } from 'react-router-dom';
import { auth } from '~/firebase'
export default class SignIn extends React.Component {
state = {
uiShown: false,
redirect: false
}
ui // = new firebaseui.auth.AuthUI(auth)
uiConfig = { ... }
constructor(props) {
super(props)
console.debug('constructor')
this.ui = new firebaseui.auth.AuthUI(auth)
}
componentDidMount() {
this.ui.start('#firebaseui-auth-container', this.uiConfig)
}
componentWillUnmount() {
console.debug('will unmount')
this.ui.delete().then(() => console.debug('deleted'))
}
render() {
return (
<>
<div id="firebaseui-auth-container"/>
{!this.state.uiShown && <div id="loader">Loading...</div>}
{this.state.redirect && <Redirect to="/dashboard"/>}
</>
)
}
}
My app layout is such that I have some public and private pages. If private page is accessed when user is not logged in, he gets redirected to /signin page. The problem is when I am on /signin page and I access one of the other private pages - I am redirected back immediately and the tree containing the SignIn component gets re-mounted.
delete returns a promise which resolves on deletion. You have to wait for it to resolve before you initialize.
Right, but why is that asynchronous? That doesn't go well with react lifecycle methods. I will have to keep a global reference to the promise then I guess.
Is there a better suggested approach?
Take a look at the code. It is open sourced: https://github.com/firebase/firebaseui-web/blob/master/javascript/widgets/authui.js#L812
We call signOut underneath on an internal Auth instance. The operation is asynchronous. Nothing we can do about it.
Thank you for clarification
I was able to come around this issue with pushing the instantiation at the end of execution queue.
componentDidMount() {
setTimeout(() => {
this.ui = new firebaseui.auth.AuthUI(auth)
this.ui.start('#firebaseui-auth-container', this.uiConfig)
}, 0)
}
componentWillUnmount() {
this.ui.delete()
}
You could also keep a static reference to the delete promise. something like:
```js
export default class SignIn extends React.Component {
// ...
// Resolved unless an instance of FirebaseUI is being deleted.
static firebaseUiDeleted = Promise.resolve();
componentDidMount() {
SignIn.firebaseUiDeleted.then(() => {
this.ui = new firebaseui.auth.AuthUI(auth)
this.ui.start('#firebaseui-auth-container', this.uiConfig)
})
}
componentWillUnmount() {
SignIn.firebaseUiDeleted = this.ui.delete()
}
}
Most helpful comment
You could also keep a static reference to the delete promise. something like:
```js
export default class SignIn extends React.Component {
// ...
// Resolved unless an instance of FirebaseUI is being deleted.
static firebaseUiDeleted = Promise.resolve();
componentDidMount() {
SignIn.firebaseUiDeleted.then(() => {
this.ui = new firebaseui.auth.AuthUI(auth)
this.ui.start('#firebaseui-auth-container', this.uiConfig)
})
}
componentWillUnmount() {
SignIn.firebaseUiDeleted = this.ui.delete()
}
}