1

I need your ideasssssssss.

renderIt = () => {
    if(!this.state.user){
      return <Login />
    }else {
      return <Home />
    }
  }

here I check is the user is logged in, if he is not logged in <Login /> is displayed, when he logs itself in, then <Home /> is displayed.

Problem is, when I go log out, and refresh, I see <Home/> page for a fraction of a second even if I am not logged in.

componentDidMount = () => {
      this.authListener();
  }

 authListener = () => {
    firebase
      .auth()
      .onAuthStateChanged((user) => user ? this.setState({user}) : this.setState({user: null}))
  }
  • How do you set `this.state.user`? – Frank van Puffelen Sep 20 '20 at 23:52
  • I've updated the post, check it out – Haris Hamzić Sep 20 '20 at 23:56
  • What you're describing is the exact opposite of what I'd expect. Firebase should initially call your state changed listener with `null`, while it checks the user's authentication state. Then, once it has restored the state, it calls you with the user. So you should briefly see the Login screen and then the home screen, not the other way around. If that is really what you see, can you set up a repro on a site like jsbin or stackblitz, so I can have a look? – Frank van Puffelen Sep 21 '20 at 00:13
  • Here you go, try clicking the refresh button and you'll end up seeing YOU ARE LOGGED IN and after ... ms you will see the login form. https://stackblitz.com/edit/react-xutkna?file=src/App.js – Haris Hamzić Sep 21 '20 at 00:21

2 Answers2

1

it's because !this.state.user true initially and until firebase auth finishes its work it will show you <Home/>.

The solution is to use a loading (some spinner animation) component initially until the firebase auth finished

if(this.state.user===null){
//create Loading component first before using it here
  return <Loading />
}else if(!this.state.user){
  return <Login />
}else {
  return <Home />
}
  • This might not be a better way to handle user authentication, it's just to answer your question
Besufkad Menji
  • 1,433
  • 9
  • 13
1

The problem is in your initial state, which is:

class App extends Component {
  state = {
    user: {}
  }
  ...

Since you then check for this.state.user in the rendering code, you end up comparing (!{}) which is false.

I highly recommend keeping this code as simple as possible, following these rules:

  • this.state.user represents the current user object.
  • if there is no current user, this.state.user is null.

In code:

class App extends Component {
  state = {
    user: null
  }

  componentDidMount = () => {
      this.authListener();
  }

  authListener = () => {
    firebase
      .auth()
      .onAuthStateChanged((user) => this.setState({user}));
  }
  ...

Also see the updated working code at: https://stackblitz.com/edit/react-1bv4bb?file=src/App.js

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • One more question, because it's connected to this topic, is it possible to update the retrieved object? .onAuthStateChanged((user)) this retrieved user, I saw that already holds properties like profilephoto, phone number, displayName etc. – Haris Hamzić Sep 21 '20 at 21:02
  • You can update the existing properties with [`updateProfile`](https://pub.dev/documentation/firebase_auth/latest/firebase_auth/User/updateProfile.html) and other methods on the `User` class, but you can't add new properties. If you want that you'll either store them as custom claims (if they're security related and small) or in the database. See https://stackoverflow.com/q/37415863 and some more of these: https://www.google.com/search?q=firebase+add+property+to+user – Frank van Puffelen Sep 21 '20 at 22:10