6

我从 cli 创建了一个带有选项卡启动器模板的 ionic react 应用程序,并向现有结构添加了登录功能。

我做了什么 :

应用程序.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>
);

问题是我在登录屏幕上看到了所有选项卡。我希望标签仅在用户登录后显示。

工作演示在这里

4

2 回答 2

11

您需要将您的私人标签分离到另一个组件中:

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;

之后,您可以在App.tsx中创建一个路由,如果用户登录,您可以在其中有条件地呈现私有选项卡。否则,将呈现登录页面:

应用程序.tsx

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

此时,您希望进行某种状态管理设置(Redux、通过 React 钩子进行自定义状态管理等),因为您需要将isLoggedIn状态放在 App 组件中,但要从 Login 组件修改它(这很混乱)仅快速使用道具)。

所以作为一个简单的例子(你肯定可以做得更好),我创建了一个简单的上下文,我在其中注入了更新状态user的函数:isLoggedIn

应用程序.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>
  );
};

我还需要创建一个顶级App组件,以便我可以提供上下文并立即在IonApp组件内使用它。之后,我可以简单地使用组件user内部的上下文Login并在登录时更新状态:

const user = useContext(UserContext);

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

这是您的分叉演示

于 2020-06-13T15:45:53.363 回答
0

<IonTabs />在登录屏幕上时不要包裹路由。

一个警告是,Ionic 期望路由相关组件的特定嵌套(至少根据我的经验)。具体来说,只能有一个<IonRouterOutlet />(当您这样做时,应用程序变得无响应并且不再接收点击)。解决这个问题的一种方法是根据用户是否登录来渲染包装在不同组件中的相同路由。在下面的示例中,我在没有<IonTabs />用户未登录的情况下渲染树。注意我在任何一种情况下都声明了相同的路由(否则会导致奇怪的重定向循环)。

// Determine if user is logged in, e.g.
const auth = useAuth()
const showTabs = !!auth.user

// Always declare same routes
const routes = (
  <>
    <Route path="/login" exact />
    <ProtectedRoute path="/protected" exact />
  </>
)

// Adhere to Ionic's nesting requirements
// Tabs: IonReactRouter -> IonTabs -> IonRouterOutlet -> Route
// No tabs: IonReactRouter -> IonRouterOutlet -> Route
return (
  <IonReactRouter>
    {showTabs ? (
      <IonTabs>
        <IonRouterOutlet>{routes}</IonRouterOutlet>
        {tabBar}
      </IonTabs>
    ) : (
      <IonRouterOutlet>{routes}</IonRouterOutlet>
    )}
  </IonReactRouter>
)
于 2021-10-13T12:06:10.333 回答