-1

In my project after login, the Navbar has to change.

class App extends React.Component {
  render(){
        return(
          <BrowserRouter>
            <div className="App">
              {firebase.auth().onAuthStateChanged(user =>{
                if(user){
                  return(
                    <UserNavBar/>
                  )
                }else{
                  return(
                    <CommonNavBar/>
                  )
                }
              })}
              <Route path="/Home" component={Home}/>
              <Route path="/Photos" component={Photos}/>
              <Route path="/RegisterPage" component={RegisterPage}/>
              <Route path="/LoginPage" component={LoginPage}/>
              <Route path="/Account" component={Account}/>
            </div>
          </BrowserRouter>
        )
    } 
}

export default App

But nothing is returned, I tried to debug it many times:

  • The system detects that the user is login
  • If I console log after the if it's work
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
Gregoirelpv
  • 92
  • 1
  • 10

2 Answers2

2

I believe the problem is that you misunderstand the Async code (Promises) and template rendering concept. You can't just return some component out of Promise and expect it to appear in the result. Here is a bit different approach that you can use for start:

import React, { useState, useEffect } from 'react';

const NavBar = ({ user, isLoading }) => {
    const [isLoading, setIsLoading] = useState(true);
    const [user, setUser] = useState(null);

    useEffect(() => {
        firebase.auth().onAuthStateChanged(user =>{
            setUser(user);
            setIsLoading(false);
        });
    }, []);

    if (isLoading) {
        return <div>Some navigation placeholder without content while info is loading....</div>
    }

    return user ? <UserNavBar/> : <CommonNavBar/>;
}

const App = () => {
    return(
        <div className="App">
            <NavBar />

            <BrowserRouter>
                <Route path="/Home" component={Home}/>
                <Route path="/Photos" component={Photos}/>
                <Route path="/RegisterPage" component={RegisterPage}/>
                <Route path="/LoginPage" component={LoginPage}/>
                <Route path="/Account" component={Account}/>
            </BrowserRouter>
        </div>
    )
};

export default App

Important things here:

  1. In onAuthStateChanged we don't return some component, but we set the state data with user information. Setting state would re-render component and depends on current existing user data on hands, component would render the result.
  2. While data is loading, it's a good practice to show some placeholder (empty nav) to avoid too much glitching
  3. We've extracted Navigation data and rendering logic to separate component - to not pollute common App component with very specific code.
  4. Code looks a bit differently because of Hooks API which are more "fancy and popular" these days in React community.

In case of questions, feel free to add comments, I'd be glad to help.

steppefox
  • 1,784
  • 2
  • 14
  • 19
2

Make sure whenever you are doing Async operations in a component which is in your case a class component, do the same in componetDidMount(). then change the state of your component by using setState.

you can see the lifecycle of the react here: https://reactjs.org/docs/state-and-lifecycle.html

for eg:

class App extends React.Component {
  constructor(props){
    super(props);
    this.state = {
      user: null
    }
  }
  componentDidMount() {
    firebase.auth().onAuthStateChanged(user => user && this.setState({user}) )
  }
  render(){
    const { user } = this.state;
    return(
      <BrowserRouter>
        <div className="App">
          {user ? <UserNavBar/> : <CommonNavBar/>}
          <Route path="/Home" component={Home}/>
          <Route path="/Photos" component={Photos}/>
          <Route path="/RegisterPage" component={RegisterPage}/>
          <Route path="/LoginPage" component={LoginPage}/>
          <Route path="/Account" component={Account}/>
        </div>
      </BrowserRouter>
    )} 
}

export default App

or you can use hooks instead of class component.

Ravi Singh
  • 1,049
  • 1
  • 10
  • 25