React Navigation
本指南涵盖了在使用 Ionic 和 React 构建的应用中路由是如何工作的。
IonReactRouter 底层使用了流行的 React Router 库。通过 Ionic 和 React Router,你可以创建具有丰富页面转换效果的多页面应用。
你所了解的关于使用 React Router 进行路由的知识都可以沿用至 Ionic React。让我们来看看一个 Ionic React 应用的基础知识以及路由是如何与之协同工作的。
Ionic React 中的路由
下面是一个示例 App 组件,它定义了一个指向 "/dashboard" URL 的单一路由。当你访问 "/dashboard" 时,该路由会渲染 DashboardPage 组件。
App.tsx
const App: React.FC = () => (
<IonApp>
<IonReactRouter>
<IonRouterOutlet>
<Route path="/dashboard" component={DashboardPage} />
<Redirect exact from="/" to="/dashboard" />
</IonRouterOutlet>
</IonReactRouter>
</IonApp>
);
在 Route 之后,我们直接定义了默认的 Redirect,当用户访问应用的根 URL ("/") 时,它会将用户重定向到 "/dashboard" URL。
这个重定向还设置了 exact 属性,这意味着 URL 必 须与 from 属性(或者如果在 Route 上使用 exact,则与 path 属性)精确匹配,此路由才算匹配。如果没有它,这个重定向会为每个路由渲染,因为每个路由都以 "/" 开头。
你也可以根据条件(例如检查用户是否已认证)从 Route 的 render 方法中以编程方式进行重定向:
<Route
exact
path="/dashboard"
render={(props) => {
return isAuthed ? <DashboardPage {...props} /> : <LoginPage />;
}}
/>
IonReactRouter
IonReactRouter 组件封装了 React Router 中传统的 BrowserRouter 组件,并为应用设置路由。因此,请使用 IonReactRouter 替代 BrowserRouter。你可以向 IonReactRouter 传递任何属性,这些属性将被传递给底层的 BrowserRouter。
嵌套路由
在 Dashboard 页面内部,我们定义了更多与应用此特定部分相关的路由:
DashboardPage.tsx
const DashboardPage: React.FC = () => {
return (
<IonPage>
<IonRouterOutlet>
<Route exact path="/dashboard" component={UsersListPage} />
<Route path="/dashboard/users/:id" component={UserDetailPage} />
</IonRouterOutlet>
</IonPage>
);
};
这里,我们又定义了几个路由,指向仪表盘部分内的页面。请注意,我们需要在路径中定义完整的路由,即使我们是通过该 URL 到达此页面的,也不能省略 "/dashboard"。React Router 需要完整路径,不支持相对路径。
但是,我们可以使用 match 对象的 url 属性来提供用于渲染组件的匹配 URL,这在处理嵌套路由时会很有帮助:
const DashboardPage: React.FC<RouteComponentProps> = ({ match }) => {
return (
<IonPage>
<IonRouterOutlet>
<Route exact path={match.url} component={UsersListPage} />
<Route path={`${match.url}/users/:id`} component={UserDetailPage} />
</IonRouterOutlet>
</IonPage>
);
};
这里,match.url 包含的值是 "/dashboard",因为这是用于渲染 DashboardPage 的 URL。
这些路由被分组在一个 IonRouterOutlet 中,我们接下来会讨论它。
IonRouterOutlet
IonRouterOutlet 组件为渲染 Ionic "页面" 的路由提供了一个容器。当一个页面位于 IonRouterOutlet 中时,该容器控制页面之间的过渡动画,以及控制页面何时被创建和销毁,这有助于在视图之间来回切换时保持状态。
上面的 DashboardPage 展示了一个用户列表页面和一个详情页面。在两个页面之间导航时,IonRouterOutlet 提供适当的平台页面过渡效果,并保持前一个页面的状态不变,以便当用户导航回列表页面时,它显示为离开时的相同状态。
一个 IonRouterOutlet 应该只包含 Route 或 Redirect。任何其他组件应该作为 Route 渲染的结果进行渲染,或者放在 IonRouterOutlet 外部。
后备路由
一个常见的路由用例是提供一个"后备"路由,以便在导航到的位置与定义的任何路由都不匹配时进行渲染。
我们可以通过将一个不带 path 属性的 Route 组件作为 IonRouterOutlet 内定义的最后一个路由来定义一个后备路由。
DashboardPage.tsx
const DashboardPage: React.FC<RouteComponentProps> = ({ match }) => {
return (
<IonRouterOutlet>
<Route exact path={match.url} component={UsersListPage} />
<Route path={`${match.url}/users/:id`} component={UserDetailPage} />
<Route render={() => <Redirect to={match.url} />} />
</IonRouterOutlet>
);
};
在这里,我们看到,如果某个位置不匹配前两个 Route,IonRouterOutlet 会将 Ionic React 应用重定向到 match.url 路径。
你也可以提供一个要渲染的组件,而不是提供重定向。
const DashboardPage: React.FC<RouteComponentProps> = ({ match }) => {
return (
<IonRouterOutlet>
<Route exact path={match.url} component={UsersListPage} />
<Route path={`${match.url}/users/:id`} component={UserDetailPage} />
<Route component={NotFoundPage} />
</IonRouterOutlet>
);
};
IonPage
IonPage 组件封装了 Ionic React 应用中的每个视图,并使页面过渡和堆栈导航能够正常工作。使用路由导航到的每个视图都必须包含一个 IonPage 组件。
IonPage 对于正确的样式也是必需的。它提供了一个 flex 容器,确保页面内容(例如 IonContent)大小合适,并且不会与其他 UI 元素(如 IonTabBar)重叠。
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar } from '@ionic/react';
import React from 'react';
const Home: React.FC = () => {
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonTitle>Home</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent className="ion-padding">Hello World</IonContent>
</IonPage>
);
};
export default Home;
导航
在 Ionic React 应用中路由到不同视图有几种可用的选项。这里,UsersListPage 使用了 IonItem 的 routerLink 属性来指定当该项目被点击时要导航到的路由:
UsersListPage.tsx
const UsersListPage: React.FC = () => {
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonTitle>Users</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent>
<IonList>
<IonItem routerLink="/dashboard/users/1">
<IonLabel>User 1</IonLabel>
</IonItem>
<IonItem routerLink="/dashboard/users/2">
<IonLabel>User 2</IonLabel>
</IonItem>
</IonList>
</IonContent>
</IonPage>
);
};
其他具有 routerLink 属性的组件包括 IonButton、IonCard、IonRouterLink、IonFabButton 和 IonItemOption。
这些组件中的每一个还有一个 routerDirection 属性,用于显式设置要使用的页面过渡类型("forward"、"back" 或 "root")。
除了这些具有 routerLink 属性的组件之外,你还可以使用 React Router 的 Link 组件在视图之间导航:
<Link to="/dashboard/users/1">User 1</Link>
我们建议尽可能使用上述方法之一进行路由。这些方法的优点是它们都渲染一个锚点 (<a>) 标签,这对于整个应用的可访问性非常有利。
一个编程式的导航选项是使用 React Router 通过路由提供给其渲染组件的 history 属性。
<IonButton
onClick={(e) => {
e.preventDefault();
history.push('/dashboard/users/1');
}}
>
Go to User 1
</IonButton>
history 是一个属性。
使用 history.go 导航
React Router 使用 history 包,它有一个 history.go 方法,允许开发者在应用历史记录中向前或向后移动。让我们看一个例子。
假设你有以下应用历史记录:
/pageA --> /pageB --> /pageC
如果你在 /pageC 上调用 router.go(-2),你将回到 /pageA。如果你随后调用 router.go(2),你将到达 /pageC。
在 Ionic React 中目前不支持使用 history.go()。有兴趣看到这个功能被添加到 Ionic React 中吗?在 GitHub 上告诉我们!
URL 参数
在 Dashboard 页面中定义的第二个路由有一个 URL 参数(路径中的 ":id" 部分)。URL 参数是 path 的动态部分,当用户导航到像 "/dashboard/users/1" 这样的 URL 时,"1" 被保存到一个名为 "id" 的参数中,可以在路由渲染的组件中访问它。让我们看看如何做到这一点。
UserDetailPage.tsx
interface UserDetailPageProps
extends RouteComponentProps<{
id: string;
}> {}
const UserDetailPage: React.FC<UserDetailPageProps> = ({ match }) => {
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonTitle>User Detail</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent>User {match.params.id}</IonContent>
</IonPage>
);
};
match 属性包含有关匹配路由的信息,包括 URL 参数。我们在这里获取 id 参数并将其显示在屏幕上。
注意我们如何使用 TypeScript 接口来强类型化 props 对象。该接口在组件内部为我们提供了类型安全和代码补全。