Language: ENCN

Navigation Router

With Framework7 & React.js, we are already composing our application with components. All we need to do is map our components to the routes. Here's a basic example:

//Components.jsx
export const MainViews = () => (
  <Views>
    {/* Current View/Router */}
    <View>
      {/* All pages are rendered inside of Pages */}
      <Pages>
        {/* Initial Page /*}
        <Page>
          ...
          <Link href="/about/">About App</Link>
          <Link href="/login/">Login</Link>
        </Page>
      </Pages>
    </View>
  </Views>              
);

// Create Component for About page
export const About = () => (
  <Page name="about">...</Page>
);

// Create Component for Login page
export const Login = () => (
  <Page name="login">...</Page>
);

Now we need to map components to routes. It should be done in routes parameter on App Initialization

import {MainViews, About, Login} from './Components';

const App = () => (
  <Framework7App routes={[
    {
        path: '/about/',
        component: About
    },
    {
        path: '/login/',
        component: Login
    }
  ]}>
    <MainViews />
  </Framework7App>
);
  • Note that route components are intended to load Page components only. If you want to load other components in a route, they must be added as nested routes within a page route.

  • All pages are rendered inside of the Pages component of the current (or specified) View

  • Only one Pages component is allowed inside of one View

  • You may have as many Views as required (e.g. in Popup, in Side Panels)

Dynamic Route Matching

Very often we will need to map routes with the given pattern to the same component. In specified routes we can use a dynamic segment in the path to achieve that.

Let's say we have the following link:

<Link href="/user/45/posts/28/?sort=first#opened">Read More</Link>

And the following pattern in specified route path:

import {PostPage} from './Post';

let currentRoute;

export const getCurrentRoute = () => currentRoute;

const App = () => (
  <Framework7App onRouteChange={route => currentRoute = route} routes={[
    {
      // We can use pattern here:
      path: '/user/:userId/posts/:postId',
      component: PostPage
    }
  ]}>
    <MainViews />
  </Framework7App>
);

We can now access these route parameters in our PostPage component:

//Post.jsx
import {getCurrentRoute} from './App'

const Post = (props) => {
  const route = getCurrentRoute();

  return (
    <Page>
      <Navbar title="Post" />
      <ul>
        <li>Route: {route.route}</li>
        <li>Url: {route.url}</li>
        <li>Path: {route.path}</li>
        <li>User ID: {route.params.userId}</li>
        <li>Post ID: {route.params.postId}</li>
        <li>Query: {JSON.stringify(route.query)}</li>
        <li>Hash: {route.hash}
      </ul>
      {/* Route params are also passed as component props: */}
      <p>User ID: {props.userId}</p>
      <p>Post ID: {props.postId}</p>
    </Page>
  );
};

And the output will be:

...
<ul>
  <li>Route: /user/:userId/posts/:postId</li>
  <li>Url: /user/45/posts/28/?sort=first#opened</li>
  <li>Path: /user/45/posts/28/</li>
  <li>User ID: 45</li>
  <li>Post ID: 28</li>
  <li>Query: {"sort":"first"}</li>
  <li>Hash: opened</li>
</ul>
<p>User ID: 45</p>
<p>Post ID: 28</p>
...

The current route has the following properties:

Nested Routes

Child components within a page can be controlled via routes. Currently, this is only supported for tabs, but other components may be added in the future.

Tabs

The child components that render within a tab on a page can be controlled via routes. For example, consider these Vue components:

{/* Tabs.jsx /*}
export const Tabs = () => (
  <Page withSubnavbar>
    <Navbar backLink="Back" title="Tab Routes" sliding />
      <Subnavbar sliding>
        <Buttons>
          <Button routeTabLink="#tab1" href="/tabs/">Tab 1</Button>
          <Button routeTabLink="#tab2" href="/tabs/tab-2/">Tab 2</Button>
          <Button routeTabLink="#tab3" href="/tabs/tab-3/">Tab 3</Button>
        </Buttons>
      </Subnavbar>
    </Navbar>

    <Tabs>
      <Tab routeTabId="tab1" />
      <Tab routeTabId="tab2" />
      <Tab routeTabId="tab3" />      
    </Tabs>
  </Page>
);                       

{/* Tab1Content.jsx /*}
export const Tab1Content = () => (
  <p>Tab 1 Content</p>
);


{/* Tab2Content.jsx /*}
export const Tab2Content = () => (
  <p>Tab 2 Content</p>
);

{/* Tab3Content.jsx /*}
export const Tab3Content = () => (
  <p>Tab 3 Content</p>
);      

With the route definitions below, the URL can control which tab content component gets rendered:

var routes = [
  ...
  {
    path: '/tabs/',
    component: Tabs,
    tabs: [
      {
        path: '/',
        tabId: 'tab1',
        component: Tab1Content
      },
      {
        path: '/tab-2/',
        tabId: 'tab2',
        component: Tab2Content
      },
      {
        path: '/tab-3/',
        tabId: 'tab3',
        component: Tab3Content
      }
    ]
  }
  ...
];

Here are the results for different URL paths beneath the Tabs page URL:

It is also possible to have multiple child routes for a tab route:

var routes = [
  ...
  {
    path: '/tabs/',
    component: Tabs,
    tabs: [
      {
        path: '/',
        tabId: 'tab1',
        component: Tab1Content
      },
      {
        path: '/tab-2/',
        tabId: 'tab2',
        component: Tab2Content
      },
      {
        path: '/tab-3/',
        tabId: 'tab3',
        routes: [
          {
            path: '/',
            component: Tab3Content
          },
          {
            path: '/tab3-alternate-content/',
            component: Tab3AlternateContent
          }
        ]
      }
    ]                                  
  }
  ...
];

Here are the results for URL paths that target the different child routes of the tab3 route:

Tab routes are also supported on Tabbars:

{/* Tabbar.jsx */}
const Tabbar = () => (
  <Page tabbar-fixed>
    <Navbar backLink="Back" title="Tabbar Routes" sliding />

    <Block tabs>
      <Tab routeTabId="tab1" />
      <Tab routeTabId="tab2" />
      <Tab routeTabId="tab3" />
    </Block>

    <Toolbar tabbar labels>
      <Link href="/tabbar/" routeTabLink="#tab1" text="Tab 1" />
      <Link href="/tabbar/tab-2/" routeTabLink="#tab2" text="Tab 2" />
      <Link href="/tabbar/tab-3/" routeTabLink="#tab3" text="Tab 3" />
    </Toolbar>

  </Page>
);

Router API

It is also possible to programatically control routing via the Router API. For more info about accessing the Framework7 instance, see the Initialize App section

import {getFramework7} from './App';

<Link onClick={() => getFramework7().mainView.router.loadPage('/about/')}>About</Link>
<Link onClick={() => getFramework7().mainView.router.back()}>Go Back</Link>

Framework7 Redux

If your app uses Redux, you should consider using the routing functionality in Framework7 Redux, which allows routing to be controlled via actions like so:

store.dispatch(navigateTo('/about/'));
store.dispatch(goBack());