rakannimer / react-firebase

🔥Declarative React bindings for Firebase Auth & Realtime Database.

Home Page:https://react-firebase-js.com/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Login flow

andrewhamili opened this issue · comments

Hi. I am developing a react app with firebase login. I just want to ask if it is possible that before my login page shows, firebase will check if it is authenticated and it will then redirect to the Orders page. Here is my website:

https://test.hamiliserver.com/#/

import React, { Component, Fragment} from 'react';
import logo from './logo.svg';
import './App.css';
import {NavLink} from 'react-router-dom'
import {withRouter, BrowserRouter, Route, Switch, Redirect} from 'react-router-dom';
import history from 'history';

import Order from './Order';
import Products from './Products';
import NoPage from './NoPage';
import AddProduct from './AddProduct';
import Geography from './Geography';
import Navigation from './Navigation';
import Login from './Login';
import {AceFurnitureAPI} from './API/AceFurnitureAPI';

import * as firebase from "firebase/app";
import "firebase/auth";
import {
  FirebaseAuthProvider,
  FirebaseAuthConsumer,
  IfFirebaseAuthed,
  IfFirebaseAuthedAnd
} from "@react-firebase/auth";
import { config } from "./Firebase/config";
import LoadingModal from "./component/LoadingModal";


class App extends Component {

  constructor(props){
    super(props);
    this.userVerification=AceFurnitureAPI.userVerification.bind(this);
    this.state={loading:true};
    this.closeModal=this.closeModal.bind(this);

  }

  closeModal(){
    console.log('closeModal');
    this.setState({loading:false});
    console.log('loading: ' + this.state.loading);
  }

  render() {

    return(        
        <FirebaseAuthConsumer>
          {({isSignedIn, user, providerId})=>

            isSignedIn === true ?
            
            <div class="bg-dark">
                  <Switch >
                    <Route exact path="/" component={Order}/>
                    <Route exact path="/Order" component={Order}/>
                    <Route exact path="/Products" component={Products}/>
                    <Route exact path="/AddProduct" component={AddProduct}/>
                    <Route exact path="/geography" component={Geography}/>
                    <Route component={NoPage}/>
                  </Switch>
                  
                  <Navigation />
                </div>
                :  <Fragment><Login /><Switch><Route exact path="/Login" component={Login} /><Route component={NoPage} /></Switch></Fragment>
            
          }
        </FirebaseAuthConsumer>
    );
  }
}

export default App;

It is the same as your auth example. When the page loads, it will display isSignedIn=false, but after some seconds it will show isSignedIn=true.

Repository seems inactive

In what part of the code can I put firebase.auth().currentUser?

It would probably need a PR here to setState or initialize state based on what firebase.auth().currentUser returns before listening to the auth stream. If it returns null then the user is not logged in else we would need to set the state with the contents of currentUser.

If you would like to submit a PR I'd be happy to merge it. If not I will get to this this week and get back to you here.

Meanwhile, if you want a quick fix in your app, you could temporarily do something like this :

class App extends Component {
  constructor(props){
    super(props);
    this.userVerification=AceFurnitureAPI.userVerification.bind(this);
    this.state={loading:true, isSignedInInitial:firebase.auth().currentUser !== null};
    this.closeModal=this.closeModal.bind(this);

  }

  closeModal(){
    console.log('closeModal');
    this.setState({loading:false});
    console.log('loading: ' + this.state.loading);
  }

  render() {

    return(        
        <FirebaseAuthConsumer>
          {({isSignedIn, user, providerId})=>

            (isSignedIn === true || this.state.isSignedInInitial === true) ?
            
            <div class="bg-dark">
                  <Switch >
                    <Route exact path="/" component={Order}/>
                    <Route exact path="/Order" component={Order}/>
                    <Route exact path="/Products" component={Products}/>
                    <Route exact path="/AddProduct" component={AddProduct}/>
                    <Route exact path="/geography" component={Geography}/>
                    <Route component={NoPage}/>
                  </Switch>
                  
                  <Navigation />
                </div>
                :  <Fragment><Login /><Switch><Route exact path="/Login" component={Login} /><Route component={NoPage} /></Switch></Fragment>
            
          }
        </FirebaseAuthConsumer>
    );
  }
}

export default App;

Okay. I will try the quick fix while waiting for your update. Thanks.

It's been over a year and I'm guessing you never got around to making the change. I'm issuing a PR (#141) with your suggested fix of defaulting the state to the result of firebase.auth().currentUser.

For the isSignedIn key, I've converted firebase.auth().currentUser to a boolean with double negation and for the user key, the actual User object from Firebase Auth is attached to it.

@infinity7998

I also did the solution of @rakannimer in comment #19 (comment)

But there is a small issue with that:
While the user is already logged in, the "Login" component is still showing for a second and then update and rerender with the "else" condition.

How can I prevent this behavior?

@infinity7998

I also did the solution of @rakannimer in comment #19 (comment)

But there is a small issue with that:
While the user is already logged in, the "Login" component is still showing for a second and then update and rerender with the "else" condition.

How can I prevent this behavior?

Did you try running the example in the demo? When you run it, does it behave as you'd expect?

@infinity7998

This is the code:

function App() {
  return (
    <FirebaseAuthProvider {...firebaseConfig} firebase={firebase}>
      <FirebaseAuthConsumer>
        {({ isSignedIn, user, providerId }) => {
          return isSignedIn === false ? (
            <LoginPage />
          ) : (
            <ShowLists />
          );
        }}
      </FirebaseAuthConsumer>
    </FirebaseAuthProvider>
  );
}

Assuming the user is already logged in, the "LoginPage" component is shown for 0.5sec on each rendering the page, and then the "ShowLists" component is rendered as it should be.

So my quesition is how can I avoid this behavior?

@burekas7 You should revise code to check if providerId is null or not. Something like this:

    return (
      <FirebaseAuthProvider {...firebaseConfig} firebase={firebase}>
        <FirebaseAuthConsumer>
          {({ isSignedIn, user, providerId }) => {
            <>
                {providerId ? 
                (<>
                    {isSignedIn === false ? (
                        <LoginPage />
                        ) : (
                        <ShowLists />
                        )}
                </>) : 
                (<p>Loading...</p>)}
            </>
          }}
        </FirebaseAuthConsumer>
      </FirebaseAuthProvider>
    );
  }

@andrewhamili
Thanks, the "Loading" and the additional condition makes it much better.

Closing this issue because I have already made it to work on my side, just forgot to close it.

Closing this issue because I have already made it to work on my side, just forgot to close it.

Do you use the same solution as in your last comment or anything else?

@burekas7 yes. I use it for all of my React projects.