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 という prop もあります。つまり、このルートが一致するためには、URL が from prop(もしくは Route で exact が使われている場合の path prop)と正確に一致する必要があります。すべてのルートは"/"で始まるため、これがないと、このリダイレクトはすべてのルートに対してレンダリングされます。
ユーザーが認証されているかどうかを確認するなど、条件に基づいてルートの render メソッドからプログラムでリダイレクトすることもできます:
<Route
exact
path="/dashboard"
render={(props) => {
return isAuthed ? <DashboardPage {...props} /> : <LoginPage />;
}}
/>
IonReactRouter
IonReactRouter コンポーネントは、React Router の従来の BrowserRouter コンポーネントをラップし、アプリケーションをルーティング用にセットアップします。したがって 、 BrowserRouter の代わりに IonReactRouter を使用します。任意の prop を IonReactRouter に渡すことができ、それらはベースとなる BrowserRouter に渡されます。
ルーターのネスト
DashboardPage 内で、アプリのこの特定のセクションに関連するルートをさらに定義します。
DashboardPage.tsx
const DashboardPage: React.FC = () => {
return (
<IonPage>
<IonRouterOutlet>
<Route exact path="/dashboard" component={UsersListPage} />
<Route path="/dashboard/users/:id" component={UserDetailPage} />
</IonRouterOutlet>
</IonPage>
);
};
ここでは、アプリの DashboardPage から更にコンポーネントが定義された 2 つのルートがあります。path にはルートの全体を定義する必要があり、その URL からこのページに到達した場合でも、 "/dashboard" を省略できないことに注意してください。 React Router は絶対パスを必要とし、相対パスはサポートされていません。
ただし、 match オブジェクトの url プロパティを使用して、コンポーネントをレンダリングするために match した 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 には、ユーザーリストページと詳細ページが表示されます。 2 つのページ間を移動するとき、 IonRouterOutlet は適切なプラットフォームページの遷移を提供し、前のページの状態をそのまま保持するため、ユーザーがリストページに戻ると、前のページと同じ状態で表示されます。
IonRouterOutlet には、 Route と Redirect のみを含める必要があります。 他のコンポーネントは、 Route の結果、または IonRouterOutlet の外部でレンダリングする必要があります。
Fallback Route
A common routing use case is to provide a "fallback" route to be rendered in the event the location navigated to does not match any of the routes defined.
We can define a fallback route by placing a Route component without a path property as the last route defined within an 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>
);
};
Here, we see that in the event a location does not match the first two Routes the IonRouterOutlet will redirect the Ionic React app to the match.url path.
You can alternatively supply a component to render instead of providing a redirect.
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
The IonPage component wraps each view in an Ionic React app and allows page transitions and stack navigation to work properly. Each view that is navigated to using the router must include an IonPage component.
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;
Navigation
Ionic React アプリでさまざまなビューにルーティングする場合、いくつかのオプシ ョンを使用できます。 ここで、 UsersListPageはIonItem は IonItem の routerLink prop を使用して、タップ/クリックされたときに移動するルートを指定します:
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>
);
};
Other components that have the routerLink prop are IonButton, IonCard, IonRouterLink, IonFabButton, and IonItemOption.
Each of these components also have a routerDirection prop to explicitly set the type of page transition to use ("back", "forward", or "none").
Outside of these components that have the routerLink prop, you can also use React Routers Link component to navigate between views:
<Link to="/dashboard/users/1">User 1</Link>
ルーティングは可能な限り、上記の方法のいずれかを使用することをお勧めします。 これらのアプローチの利点は、両方ともアンカー( <a> )タグをレンダリングすることです。これはアプリ全体のアクセシビリティに適しています。
ナビゲーションのためのプログラムオプションとして、React Router がルート経由でレンダリングするコンポーネントに提供する history prop を使用することもできます。
<IonButton
onClick={(e) => {
e.preventDefault();
history.push('/dashboard/users/1');
}}
>
Go to User 1
</IonButton>
history is a prop.
Navigating using history.go
React Router uses the history package which has a history.go method that allows developers to move forward or backward through the application history. Let's take a look at an example.
Say you have the following application history:
/pageA --> /pageB --> /pageC
If you were to call router.go(-2) on /pageC, you would be brought back to /pageA. If you then called router.go(2), you would be brought to /pageC.
Using history.go() in Ionic React is not supported at the moment. Interested in seeing support for this get added to Ionic React? Let us know on GitHub!
URL Parameters
Dashboard Page で定義された 2 番目のルートには、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 prop には、URL パラメーターなど、一致したルートに関する情報が含まれます。 ここで id パラメータを取得し、画面 に表示します。
Note: TypeScript インターフェイスを使用して props オブジェクトを厳密に入力する方法に注意してください。 このインターフェースにより、コンポーネント内部でタイプセーフティとコード補完が可能になります。
Linear Routing versus Non-Linear Routing
Linear Routing
If you have built a web app that uses routing, you likely have used linear routing before. Linear routing means that you can move forward or backward through the application history by pushing and popping pages.
The following is an example of linear routing in a mobile app:
The application history in this example has the following path:
Accessibility --> VoiceOver --> Speech
When we press the back button, we follow that same routing path except in reverse. Linear routing is helpful in that it allows for simple and predictable routing behaviors.
The downside of linear routing is that it does not allow for complex user experiences such as tab views. This is where non-linear routing comes into play.
Non-Linear Routing
Non-linear routing is a concept that may be new to many web developers learning to build mobile apps with Ionic.
Non-linear routing means that the view that the user should go back to is not necessarily the previous view that was displayed on the screen.
The following is an example of non-linear routing:
In the example above, we start on the Originals tab. Tapping a card brings us to the Ted Lasso view within the Originals tab.
From here, we switch to the Search tab. Then, we tap the Originals tab again and are brought back to the Ted Lasso view. At this point, we have started using non-linear routing.
Why is this non-linear routing? The previous view we were on was the Search view. However, pressing the back button on the Ted Lasso view should bring us back to the root Originals view. This happens because each tab in a mobile app is treated as its own stack. The Working with Tabs sections goes over this in more detail.
If tapping the back button simply called history.go(-1) from the Ted Lasso view, we would be brought back to the Search view which is not correct.
Non-linear routing allows for sophisticated user flows that linear routing cannot handle. However, certain linear routing APIs such as history.go() cannot be used in this non-linear environment. This means that history.go() should not be used when using tabs or nested outlets.