reactjsionic-frameworkreact-routerionic-react

Hide tabs on Login screen in Ionic React


I created an ionic react app with tabs starter template from the cli and added login functionality to the existing structure.

What I did :

App.tsx

  const App: React.FC = () => (
  <IonApp>
    <IonReactRouter>
      <IonTabs>
        <IonRouterOutlet>
          <Route path="/profile" component={Profile} exact={true} />
          <Route path="/history" component={History} />
          <Route path="/login" component={Login} exact={true} />
          <Route path="/" component={Login} exact={true} />
        </IonRouterOutlet>
        <IonTabBar slot="bottom">
          <IonTabButton tab="profile" href="/profile">
            <IonIcon icon={personCircleOutline} />
            <IonLabel>Profile</IonLabel>
          </IonTabButton>
          <IonTabButton tab="history" href="/history">
            <IonIcon icon={documentTextOutline} />
            <IonLabel>History</IonLabel>
          </IonTabButton>
        </IonTabBar>
      </IonTabs>
    </IonReactRouter>
  </IonApp>
);

The issue is that I'm seeing all the tabs on the login screen. I want the tabs to show only after the user logs in.

Working Demo here


Solution

  • You need to separate your private tabs into another component:

    mainTabs.tsx

    const MainTabs: React.FC = () => {
      return (
        <IonTabs>
          <IonRouterOutlet>
            <Redirect exact path="/" to="/profile" />
            <Route path="/profile" render={() => <Profile />} exact={true} />
            <Route path="history" render={() => <History />} exact={true} />
          </IonRouterOutlet>
          <IonTabBar slot="bottom">
            <IonTabButton tab="profile" href="/profile">
              <IonIcon icon={personCircleOutline} />
              <IonLabel>Profile</IonLabel>
            </IonTabButton>
            <IonTabButton tab="history" href="/history">
              <IonIcon icon={documentTextOutline} />
              <IonLabel>History</IonLabel>
            </IonTabButton>
          </IonTabBar>
        </IonTabs>
      );
    };
    
    export default MainTabs;
    

    After that, you can create a route inside App.tsx in which you conditionally render the private Tabs if the user is logged in. Otherwise, the Login page is rendered:

    App.tsx

    return (
      <IonApp>
        <IonReactRouter>
          <Route path="/login" component={Login} exact={true} />
          <Route path="/" component={isLoggedIn ? MainTabs : Login} />
        </IonReactRouter>
      </IonApp>
    );
    

    At this point, you want to have some sort of state management setup (Redux, custom state management through React hooks, etc.) because you need to have your isLoggedIn state inside the App component but modify it from the Login component (this get's messy real quick using props only).

    So as a quick example (you can definitely do a better job), I've created a simple user context, in which I inject the function that updates the isLoggedIn state:

    App.tsx

    interface IUserManager {
      setIsLoggedIn: Function;
    }
    
    const user: IUserManager = {
      setIsLoggedIn: () => {}
    };
    
    export const UserContext = React.createContext<IUserManager>(user);
    
    const IonicApp: React.FC = () => {
      const [isLoggedIn, setIsLoggedIn] = useState(false);
      const user = useContext(UserContext);
    
      user.setIsLoggedIn = setIsLoggedIn;
    
      return (
        <IonApp>
          <IonReactRouter>
            <Route path="/login" component={Login} exact={true} />
            <Route path="/" component={isLoggedIn ? MainTabs : Login} />
          </IonReactRouter>
        </IonApp>
      );
    };
    
    const App: React.FC = () => {
      return (
        <UserContext.Provider value={user}>
          <IonicApp />
        </UserContext.Provider>
      );
    };
    

    I also need to create a top-level App component so I can provide the context and use it right away inside the IonApp component. After that, I can simply use the user context inside the Login component and update the state on login:

    const user = useContext(UserContext);
    
    const loginClick = () => {
      if (userName === "a" && password === "a") {
        user.setIsLoggedIn(true);
      } 
    };
    

    Here is your forked demo.