This guide describes how routing works in an app built with Ionic and React.
IonReactRouter
uses the popularRouters respondLibrary under the hood. With Ionic and React Router you can create multi-page apps with rich page transitions.
Everything you know about routing with React Router is carried over to Ionic React. Let's take a look at the basics of an Ionic React app and how routing works with it.
Here is an exampleApp
Component that defines a single route to the /dashboard URL. When you go to /dashboard, the route is renderedDashboardSeite
Components.
App.tsx
art App: React.FC = () => (
<IonApp>
<IonReactRouter>
<IonRouterOutlet>
<Route Away="/Dashboard" Components={DashboardSeite} />
<Redirect I agree out="/" to="/Dashboard" />
</IonRouterOutlet>
</IonReactRouter>
</IonApp>
);
Right after theRoute
, we define our standardRedirect
, which when a user visits the app's root URL ("/"), redirects them to the "/dashboard" URL.
The forwarding has that tooI agree
prop set, which means the url must match theout
support (or theAway
support ifI agree
was used on oneRoute
) exactly for this route being a match. Without it, this redirect would be rendered for every route since every route starts with "/".
You can also programmatically redirect from a route's rendering method based on a condition, e.g. B. Check if a user is authenticated or not:
<Route
I agree
Away="/Dashboard"
make={(props) => {
returnisAuthenticated? <DashboardSeite {...props} /> : <login page />;
}}
/>
IonReactRouter
ThatIonReactRouter
Component encloses the traditionalBrowserRouter
React Router component and sets up the app for routing. Therefore useIonReactRouter
instead ofBrowserRouter
. You can pass any props toIonReactRouter
and they are passed on to the underlying assetBrowserRouter
.
On the dashboard page we define more routes related to this specific section of the app:
DashboardPage.tsx
art DashboardSeite: React.FC = () => {
return (
<IonPage>
<IonRouterOutlet>
<Route I agree Away="/Dashboard" Components={User List page} />
<Route Away="/dashboard/users/:id" Components={user details page} />
</IonRouterOutlet>
</IonPage>
);
};
Here are a few more routes defined that point to pages within the dashboard portion of the app. Note that we must define the entire route in the path and we cannot omit "/dashboard" even though we got to this page from that URL. React Router requires full paths and relative paths are not supported.
However, we can use theto suit
objectsURL
property to provide the URL matched to render a component, which is useful when working with nested routes:
art DashboardSeite: React.FC<RouteComponentProps> = ({to suit}) => {
return (
<IonPage>
<IonRouterOutlet>
<Route I agree Away={to suit.URL} Components={User List page} />
<Route Away={`${to suit.URL}/users/:id`} Components={user details page} />
</IonRouterOutlet>
</IonPage>
);
};
Here,match.url
contains the value of "/dashboard" because that was the URL used to renderDashboardSeite
.
These routes are grouped into oneIonRouterOutlet
, let's discuss that next.
IonRouterOutlet
ThatIonRouterOutlet
component provides a container for routes that render ionic "pages". When a page is in aIonRouterOutlet
, the container controls the animation of transitions between pages, as well as the creation and deletion of a page, which helps maintain state between views when switching back and forth between them.
ThatDashboardSeite
above shows a user list page and a details page. When navigating between the two pages, theIonRouterOutlet
provides the appropriate platform page transition and keeps the state of the previous page intact so that when a user navigates back to the list page, they see it in the same state that they left it.
AIonRouterOutlet
should only containRoute
s orRedirect
s. Every other component should either be rendered as a result of aRoute
or outside ofIonRouterOutlet
.
A common use case for routing is to provide a "fallback" route that is rendered if the navigated location does not match any of the defined routes.
We can define a fallback route by placing aRoute
component without aAway
-Property as the last within a defined routeIonRouterOutlet
.
DashboardPage.tsx
art DashboardSeite: React.FC<RouteComponentProps> = ({to suit}) => {
return (
<IonRouterOutlet>
<Route I agree Away={to suit.URL} Components={User List page} />
<Route Away={`${to suit.URL}/users/:id`} Components={user details page} />
<Route make={() => <Redirect to={to suit.URL} />} />
</IonRouterOutlet>
);
};
Here we see that in case a location doesn't match the first twoRoute
is theIonRouterOutlet
redirects the Ionic React app to thematch.url
Away.
You can alternatively provide a component to render instead of providing a redirect.
art DashboardSeite: React.FC<RouteComponentProps> = ({to suit}) => {
return (
<IonRouterOutlet>
<Route I agree Away={to suit.URL} Components={User List page} />
<Route Away={`${to suit.URL}/users/:id`} Components={user details page} />
<Route Components={Page not found} />
</IonRouterOutlet>
);
};
IonPage
ThatIonPage
-Component wraps each view in an Ionic React app and allows page transitions and stack navigation to work properly. Each view navigated to using the router must contain oneIonPage
Components.
import { ionic content, The IonHeader, IonPage, IonTitel, IonToolbar } out '@ionic/react';
import React out 'react';
art Heim: React.FC = () => {
return (
<IonPage>
<The IonHeader>
<IonToolbar>
<IonTitel>Heim</IonTitel>
</IonToolbar>
</The IonHeader>
<ionic content class name="ionic padding">Hallo Welt</ionic content>
</IonPage>
);
};
Export Originally Heim;
There are several options available when routing to different views in an Ionic React app. Here theUser List page
UsedIon
'srouterLink
prop to specify the route to go to when the item is tapped/clicked:
UsersListPage.tsx
art User List page: React.FC = () => {
return (
<IonPage>
<The IonHeader>
<IonToolbar>
<IonTitel>user</IonTitel>
</IonToolbar>
</The IonHeader>
<ionic content>
<Ion list>
<Ion routerLink="/Dashboard/Users/1">
<IonLabel>user 1</IonLabel>
</Ion>
<Ion routerLink="/dashboard/users/2">
<IonLabel>user 2</IonLabel>
</Ion>
</Ion list>
</ionic content>
</IonPage>
);
};
Other components that have therouterLink
support areIonButton
,IonCard
,IonRouterLink
,IonFabButton
, andIonItemOption
.
Each of these components also has onerouterDirection
prop to explicitly set the type of page transition to use ("back", "forward", or "none").
Outside of these components that have therouterLink
prop you can also use React Routershortcut
Component for navigating between views:
<shortcut to="/Dashboard/Users/1">user 1</shortcut>
We recommend using one of the above routing methods whenever possible. The advantage of these approaches is that both use an anchor (<a>
) tag suitable for general app accessibility.
A programmatic option for navigation is to usestory
prop that React Router provides to the components it renders via routes.
<IonButton
onClick={(e) => {
e.prevent default();
story.to press('/dashboard/users/1');
}}
>
walktouser 1
</IonButton>
a notice
story
is a prop.
navigate withhistory.go
React Router uses thestory
package that has onehistory.goMethod that allows developers to move forward or backward in the application history. Let's look at an example.
Suppose you have the following application history:
/ SiteA
-->/SeiteB
-->/SeiteC
if you would callrouter.go(-2)
an/SeiteC
, you would be brought back/ SiteA
. Then when you calledrouter.go(2)
, you would be brought/SeiteC
.
Usehistory.go()
in Ionic React is not currently supported. Interested in seeing support for this being added to Ionic React?Let us know on GitHub!
URL-Parameter
The second route defined on the dashboard page has a URL parameter defined (the ":id" part in the path). URL parameters are dynamic parts of theAway
, and when the user navigates to a URL like "/dashboard/users/1", the "1" is stored in a parameter called "id" that can be accessed in the component that renders the route. Let's see how this is done.
UserDetailPage.tsx
interface UserDetailPageProps
expanded RouteComponentProps<{
I would: line;
}> {}
art user details page: React.FC<UserDetailPageProps> = ({to suit}) => {
return (
<IonPage>
<The IonHeader>
<IonToolbar>
<IonTitel>user Detail</IonTitel>
</IonToolbar>
</The IonHeader>
<ionic content>user {to suit.Parameter.I would}</ionic content>
</IonPage>
);
};
Thatto suit
prop contains information about the matched route, including the URL parameters. We get theI would
param here and display it on the screen.
Notice how we use a TypeScript interface to strongly type the Props object. The interface gives us type safety and code completion within the component.
Lineares Routing
If you've built a web app that uses routing, you've probably used linear routing before. Linear routing means you can move forward or backward through the application history by moving and opening pages.
The following is an example of linear routing in a mobile app:
The application history in this example has the following path:
Accessibility
-->Voice-over
-->Network
If we press the back button, we follow the same routing path, except in the opposite direction. Linear routing is useful in that it allows for simple and predictable routing behavior.
The disadvantage of linear routing is that it doesn't allow for complex user experiences like tabbed views. This is where nonlinear routing comes into play.
Nonlinear routing
Nonlinear routing is a concept that might be new to many web developers learning to build mobile apps with Ionic.
Nonlinear routing means that the view the user should return to is not necessarily the previous view that was displayed on the screen.
The following is an example of nonlinear routing:
In the example above, we start with thatOriginal
Tab. Tapping a card brings us toTeddy Lasso
view within theOriginal
Tab.
From here we switch to theSeek
Tab. Then we tap theOriginal
tab again and are brought back toTeddy Lasso
Outlook. At this point we started using nonlinear routing.
Why is this nonlinear routing? The previous view we were on was thisSeek
Outlook. However, press the back button on theTeddy Lasso
View should bring us back to basicsOriginal
Outlook. This is because each tab in a mobile app is treated as its own stack. ThatWorking with tabssection goes into more detail.
Simply invoked when tapping the back buttonHistory.go(-1)
of theTeddy Lasso
view, we would be brought back to thatSeek
view that is not correct.
Nonlinear routing enables demanding user flows that linear routing cannot handle. Certain linear routing APIs such ashistory.go()
cannot be used in this non-linear environment. It means thathistory.go()
should not be used when using tabs or nested exits.
Which of them should I take?
We recommend keeping your application as simple as possible until you need to add nonlinear routing. Nonlinear routing is very powerful, but it also significantly increases the complexity of mobile applications.
The two most common uses of nonlinear routing are tabbed and nestedIonRouterOutlets
. We recommend using nonlinear routing only if your application satisfies the tabbed or nested router exit use cases.
For more information about tabs, seeWorking with tabs.
For more information on nested router exits, seeNested routes.
A common point of confusion when setting up routing is deciding between shared URLs or nested routes. This part of the guide explains both and will help you decide which one to use.
Shared URLs are a route configuration where routes share parts of the URL. The following is an example of a shared URL configuration:
art App: React.FC = () => {
<IonApp>
<IonReactRouter>
<IonRouterOutlet>
<Route Away="/Dashboard" I agree={Is correct}>
<Dashboard main page />
</Route>
<Route Away="/Dashboard/Statistics" I agree={Is correct}>
<Dashboard stats page />
</Route>
</IonRouterOutlet>
</IonReactRouter>
</IonApp>
}
The above routes are considered "shared" because they reuse thedashboard
piece of the url.
Nested routes
Nested routes are a route configuration where routes are listed as children of other routes. The following is an example of a nested route configuration:
art App: React.FC = () => (
<IonApp>
<IonReactRouter>
<IonRouterOutlet>
<Route Away="/dashboard/:id">
<DashboardRouterOutlet />
</Route>
</IonRouterOutlet>
</IonReactRouter>
</IonApp>
)
art DashboardRouterOutlet: React.FC = () => (
<IonRouterOutlet>
<Route Away="/Dashboard" I agree={Is correct}>
<Dashboard main page />
</Route>
<Route Away="/Dashboard/Statistics" I agree={Is correct}>
<Dashboard stats page />
</Route>
</IonRouterOutlet>
)
The routes above are nested because they are in theKinder
Array of parent route. Note that the parent route is theDashboardRouterOutlet
Component. If you nest routes, you must render another instance ofIonRouterOutlet
.
Which of them should I take?
Shared URLs are great when you want to go from Page A to Page B while maintaining the relationship between the two pages in the URL. In our previous example, a button is on the/Dashboard
page could switch to the/Dashboard/Statistics
Side. The relationship between the two pages is preserved because of a) the page transition and b) the URL.
Nested routes should be used when you want to render content in Outlet A while also wanting to render sub-content in a nested Outlet B. The most common use case you will come across is tabs. If you load a Tabs Ionic starter application you will seeIonTabBar
andIonTabs
Components rendered in the firstIonRouterOutlet
. ThatIonTabs
component renders anotherIonRouterOutlet
which is responsible for rendering the content of each tab.
There are very few use cases where nested routes make sense in mobile applications. If in doubt, use the shared URL route configuration. We strongly caution against using nested routing in contexts other than tabs, as this can quickly become confusing for navigating your app.
Working with tabs
When working with tabs, Ionic needs to know which view belongs to which tab. ThatIonTabs
Component comes in handy here, but let's see what the routing setup for it looks like:
<IonApp>
<IonReactRouter>
<IonRouterOutlet>
<Route Away="/Tabs" make={() => <tabs />} />
<Route I agree Away="/">
<Redirect to="/Tabs" />
</Route>
</IonRouterOutlet>
</IonSplitPane>
</IonReactRouter>
</IonApp>
Here ourtabs
path loads atabs
Component. We expose each tab as a route object within this component. In this example we name the pathtabs
, but this can be customized.
Let's start by looking at ourstabs
Components:
import { Redirect, Route } out 'react-router-dom';
import {
ionic content,
IonIcon,
IonLabel,
IonRouterOutlet,
IonTabBar,
IonTabButton,
IonTabs
} out '@ionic/react';
import { IonReactRouter } out '@ionic/react-router';
import {Ellipse,square,triangle} out 'ionicons';
import Tab1 out './pages/Tab1';
import Tab2 out './pages/Tab2';
import tab3 out './pages/Tab3';
art tabs: React.FC = () => (
<ionic content>
<IonTabs>
<IonRouterOutlet>
<Redirect I agree Away="/Tabs" to="/Tabs/Tab1" />
<Route I agree Away="/Tabs/Tab1">
<Tab1 />
</Route>
<Route I agree Away="/tabs/tab2">
<Tab2 />
</Route>
<Route Away="/tabs/tab3">
<tab3 />
</Route>
<Route I agree Away="/Tabs">
<Redirect to="/Tabs/Tab1" />
</Route>
</IonRouterOutlet>
<IonTabBar Slot="bottom">
<IonTabButton Tab="Table 1" href="/Tabs/Tab1">
<IonIcon Symbol={triangle} />
<IonLabel>Tab 1</IonLabel>
</IonTabButton>
<IonTabButton Tab="tab2" href="/tabs/tab2">
<IonIcon Symbol={Ellipse} />
<IonLabel>Tab 2</IonLabel>
</IonTabButton>
<IonTabButton Tab="tab3" href="/tabs/tab3">
<IonIcon Symbol={square} />
<IonLabel>Tab 3</IonLabel>
</IonTabButton>
</IonTabBar>
</IonTabs>
</ionic content>
);
Export Originally tabs;
If you've worked with the Ionic Framework before, this should look familiar. We create oneIonTabs
component and offer aIonTabBar
. ThatIonTabBar
offersIonTabButton
components, each with aTab
property associated with the corresponding tab in the router configuration. We also offer oneIonRouterOutlet
giveIonTabs
an outlet to render the different tab views.
How tabs work in Ionic
Each tab in Ionic is treated as an individual navigation stack. This means if you have three tabs in your application, each tab will have its own navigation stack. Within each stack, you can navigate forward (move a view) and backward (open a view).
This behavior is important to note because it differs from most tab implementations found in other web-based UI libraries. Other libraries typically manage tabs as a single history stack.
Because Ionic focuses on helping developers create mobile apps, the tabs in Ionic are designed to match the native mobile tabs as closely as possible. As a result, you may experience certain behaviors in Ionic's tabs that differ from the implementations of tabs you've seen in other UI libraries. Read on to learn about some of these differences.
Sub routes within tabs
If you add additional routes to tabs, you should write them as sibling routes with the parent tab as the path prefix. The following example defines the/tabs/tab1/view
Route as siblings of/Tabs/Tab1
Route. Since this new track has thoseTable 1
prefix, it will be rendered withintabs
component and tab 1 is still selected inIonTabBar
.
<IonTabs>
<IonRouterOutlet>
<Redirect I agree Away="/Tabs" to="/Tabs/Tab1" />
<Route I agree Away="/Tabs/Tab1">
<Tab1 />
</Route>
<Route I agree Away="/tabs/tab1/view">
<Tab1View />
</Route>
<Route I agree Away="/tabs/tab2">
<Tab2 />
</Route>
<Route Away="/tabs/tab3">
<tab3 />
</Route>
<Route I agree Away="/Tabs">
<Redirect to="/Tabs/Tab1" />
</Route>
</IonRouterOutlet>
<IonTabBar Slot="bottom">
<IonTabButton Tab="Table 1" href="/Tabs/Tab1">
<IonIcon Symbol={triangle} />
<IonLabel>Tab 1</IonLabel>
</IonTabButton>
<IonTabButton Tab="tab2" href="/tabs/tab2">
<IonIcon Symbol={Ellipse} />
<IonLabel>Tab 2</IonLabel>
</IonTabButton>
<IonTabButton Tab="tab3" href="/tabs/tab3">
<IonIcon Symbol={square} />
<IonLabel>Tab 3</IonLabel>
</IonTabButton>
</IonTabBar>
</IonTabs>
Switch between tabs
Because each tab is its own navigation stack, it's important to note that these navigation stacks should never interact. This means that there should never be a button in Tab 1 that redirects a user to Tab 2. In other words, tabs should only be switched by the user tapping a tab button on the tab bar.
A good example of this in practice are the mobile applications iOS App Store and Google Play Store. These apps both offer tabbed interfaces, but neither ever guides the user through tabs. For example, the Games tab in the iOS App Store app never directs users to the Search tab and vice versa.
Let's take a look at a few common mistakes made with tabs.
A Settings tab referenced by multiple tabs
A common practice is to create a settings view as its own tab. This is great when developers need to present multiple nested settings menus. However, other tabs should never attempt to link to the Settings tab. As mentioned above, the Settings tab should only be activated by a user tapping the appropriate tab button.
If you find that your tabs need to point to the Settings tab, we recommend making the Settings view a modal usingion-modal
. This is a practice found on the iOS App Store app. With this approach, each tab can represent the modal without breaking the mobile tab pattern where each tab is its own stack.
The following example shows how the iOS App Store app handles displaying an "Accounts" view from multiple tabs. By presenting the Account view in a modal, the app can work within mobile tab best practices to display the same view across multiple tabs.
Reuse views across tabs
Another common practice is to present the same view in multiple tabs. Developers often try to do this by containing the view in a single tab while directing other tabs to that tab. As mentioned above, this breaks the mobile tab pattern and should be avoided.
Instead, we recommend having routes in each tab that point to the same component. This is a practice done in popular apps like Spotify. For example, you can access an album or podcast from the Home, Search, and Your Library tabs. When accessing the album or podcast, users remain on this tab. The app does this by creating routes per tab and sharing a common component in the code base.
The example below shows how the Spotify app reuses the same album component to display content in multiple tabs. Note that each screenshot shows the same album but from a different tab.
Home page | Search tab |
---|---|
![]() | ![]() |
If you'd rather try the concepts and code described above for yourself, please visit ourlive exampleof the above topics on StackBlitz.
IonRouterOutlet in a tabbed view
When working in a tab view, Ionic React needs a way to tell which views belong to which tabs. We achieve this by taking advantage of the fact that the paths to aRoute
are regular expressions.
Although the syntax looks a bit odd, it's pretty simple once you get the hang of it.
For example, the routes for a view with two tabs (Sessions and Presenters) can be set up like this:
<IonRouterOutlet>
<Route Away="/:tab(sessions)" Components={sessionspage} I agree={Is correct} />
<Route Away="/:tab(sessions)/:id" Components={Session Details} />
<Route Away="/:tab(speakers)" Components={speaker list} I agree={Is correct} />
</IonRouterOutlet>
If the url navigated was "/sessions" it would match the first route and add a url parameter named "tab" with the value "sessions" to the resultto suit
pass objectsessionspage
.
When a user navigates to a session details page (e.g. "/sessions/1"), the second route adds a URL parameter named "tab" with a value of "sessions". WhenIonRouterOutlet
sees that both pages are in the same Sessions tab, it provides an animated page transition to the new view. When a user navigates to a new tab (in this case "Speakers"),IonRouterOutlet
do not know to provide the animation.
Switches in the IonRouter Outlet
SinceIonRouterOutlet
does the job of determining which routes to render, with aSwitch
from React Router has no effect when used withinIonRouterOutlet
. Switches still work as expected when used outdoorsIonRouterOutlet
.
More information
For more information on routing in React using React Router see the documentation athttps://reacttraining.com/react-router/web.
Ionic 4 und React: Navigation-Paul Halliday