Cookie Consent by Free Privacy Policy Generator 📌 RiotJS Routes


✅ RiotJS Routes


💡 Newskategorie: Programmierung
🔗 Quelle: dev.to

This article covers creating a Riot app coupled with Riot-Route, Riot's official client-side routing solution.

Before starting, make sure you have a base application running, or read my previous article Setup Riot + BeerCSS + Vite.

Client-side routing links the browser URL with the content on the page. When a user navigates the Riot application, the URL changes without requesting a new front-end from a server. This is called a SPA, for Single Page Applications: Riot handles all data updates and navigation without reloading the page, which makes the app rich and reactive!

Let's create the simplest routing example; then, we will delve into advanced production usage.

Basic Route

We aim to create the following app: a left drawer displaying links to different pages, and when a click happens on a link, the right section prints the corresponding page. The style is powered with the Material Design CSS BeerCSS:

Riot application changing route on Firefox

Write the following code in ./index.riot. The HTML comes from the BeerCSS documentation, and I added RiotJS syntax for the logic:

<index-riot>
    <router>
        <nav class="drawer left right-round border">
            <header>
                <nav>
                    <img class="circle" src="./examples/data/img-card.png"/>
                    <h6>Jon Snow</h6>
                </nav>
            </header>
            <!-- These links will trigger automatically HTML5 history events -->
            <a href="/">
                <i>inbox</i>
                <span class="max">Inbox</span>
                <b>24</b>
            </a>
            <a href="/favorite">
                <i>favorite</i>
                <span class="max">Starred</span>
                <b>3</b>
            </a>
            <a href="/sent">
                <i>send</i>
                <span class="max">Sent</span>
                <b>11</b>
            </a>
            <div class="medium-divider"></div>
            <a href="/subscription">
                <i>rocket</i>
                <span>Subscription</span>
            </a>
            <a href="/settings">
                <i>settings</i>
                <span>Settings</span>
            </a>

        </nav>
        <!-- Your application routes will be rendered here -->
        <span style="display:block;margin-left:20px;margin-top:20px">
            <route path="/"> <h2>Inbox</h2> </route>
            <route path="/favorite"> <h2>Starred</h2> </route>
            <route path="/sent"> <h2>Sent</h2> </route>
            <route path="/subscription"> <h2>Subscription</h2> </route>
            <route path="/settings"> <h2>Settings</h2> </route>
        </span>
    </router>
    <script>
        import { Router, Route } from '@riotjs/route'

        export default {
            components: { Router, Route }
        }
    </script>
</index-riot>

Source Code: https://github.com/steevepay/riot-beercss/blob/main/examples/riot-route/index.basic.riot

This example uses two Components provided by riot-route:

  • Router: The <router> wraps the Riot application and automatically detects all the clicks on links that should trigger navigation change.
  • Route: The <route path="/some/route/:params"> renders the page content if the path attribute corresponds to the current URL path. The path can accept regex, or parameters, and you can access the current route with the route object:
<route path="/:some/:route/:param"> {JSON.stringify(route.params)} </route>

<route path="/search(.*)">
  <!-- Assuming the URL is "/search?q=awesome" -->

  {route.searchParams.get('q')}
</route>

Source Code from the Riot-Route documentation

To access the current route in the Javascript section, it is possible to import the route object from '@riotjs/route':

import { Router, Route, route } from '@riotjs/route'

Advanced Route

Let's delve into advanced routing with the following requirements for a front-end:

  • Show a 404 page if a URL path does not exist.
  • Access query parameters into each page component.
  • For each route, display a Riot Component as a page.
  • Create a routing configuration file defining all routes, paths, and components.

Riot application on Google Chrome with a routing showing 404 when the page does not exist

In the first step, we will create 6 components, one for each page and another for the 404 Not Found page. Components are located in the pages directory:

pages/p-favorite.riot
pages/p-inbox.riot
pages/p-sent.riot
pages/p-settings.riot
pages/p-subscription.riot
pages/p-not-found.riot

Each component has only one title <h2> tag, for instance, the pages/p-sent.riot component looks like this:

<p-sent>
    <h2>Sent</h2>
</p-sent>

Or the pages/p-not-found.riot looks like:

<p-not-found>
    <h2> 404 Page Not Found </h2>
</p-not-found>

Then, create a global routing configuration file in the routes.js. The file returns a list of pages, and each Page has a name, a path with a long regex, and a corresponding component:

export default [
    {
      name     : 'Inbox',
      href     : '/',
      path     : '/(/?[?#].*)?(#.*)?',
      component: 'p-inbox',
      icon     : 'inbox'
    },
    {
      name     : 'Starred',
      href     : '/favorite',
      path     : '/favorite(/?[?#].*)?(#.*)?',
      component: 'p-favorite',
      icon     : 'favorite'
    },
    {
      name     : 'Sent',
      href     : '/sent',
      path     : '/sent(/?[?#].*)?(#.*)?',
      component: 'p-sent',
      icon     : 'send',
      separator: true
    },
    {
        name     : 'Subscription',
        href     : '/subscription',
        path     : '/subscription(/?[?#].*)?(#.*)?',
        component: 'p-subscription',
        icon     : 'rocket',
    },
    {
      name     : 'Settings',
      href     : '/settings',
      path     : '/settings(/?[?#].*)?(#.*)?',
      component: 'p-settings',
      icon     : 'settings'
    }
  ]

Source code: https://github.com/steevepay/riot-beercss/blob/main/examples/riot-route/routes.js

The <route> Riot component will use the path attribute. Each regex is composed of 3 parts:

  • /settings: Path of the page (Required static string)
  • (/?[?#].*): Query parameters (Optional group)
  • (#.*)?: Fragment, a section within a page (Optional group)

Now, import the routes.js, and all components into the index.riot file: Define components into the components:{} Riot Object, and load the routes into the state:{} Object:

<index-riot>
    <router>
        <nav class="drawer left right-round border">
            <header>
                <nav>
                    <img class="circle" src="./examples/data/img-card.png"/>
                    <h6>Jon Snow</h6>
                </nav>
            </header>
            <!-- Navigation bar created dynamically -->
            <template each={ page in state.pages }>
                <a href={ page.href }>
                    <i>{ page.icon }</i>
                    <span class="max">{ page.name }</span>
                </a>
                <div if={ page.separator === true } class="medium-divider"></div>
            </template>            
        </nav>
        <!-- Your application components/routes will be rendered here -->
        <span style="display:block;margin-left:20px;margin-top:20px">
            <route each={ r in state.pages  } path={ r.path }>
                <span is={ r.component } route={ route }></span>
            </route>
            <p-not-found if={ state.showNotFound } />
        </span>
    </router>
    <script>
        import { Router, Route, route, toRegexp, match } from '@riotjs/route';
        import pages from './routes.js'

        import pInbox from "./pages/p-inbox.riot";
        import pFavorite from "./pages/p-favorite.riot";
        import pSent from "./pages/p-sent.riot"
        import pSettings from "./pages/p-settings.riot"
        import pSubscription from "./pages/p-subscription.riot"
        import pNotFound from "./pages/p-not-found.riot"

        export default {
            components: { Router, Route, pInbox, pFavorite, pSent, pSettings, pSubscription, pNotFound },
            state: {
                pages,
                showNotFound: false
            },
            onMounted (props, state) {
                // ROUTING: create a stream on all routes
                this.anyRouteStream = route('(.*)')
                // ROUTING: check any route change to understand if the not found site should be displayed
                this.anyRouteStream.on.value((path) => {
                    this.update({ showNotFound: !this.state.pages.some(p => match(path.pathname, toRegexp(p?.path))) })  
                })
            },
            onUnmounted() {
                this.anyRouteStream.end()
            }
        }
    </script>
</index-riot>

Source code: https://github.com/steevepay/riot-beercss/blob/main/examples/riot-route/index.advanced.riot

This code differs a lot compared to the Basic example; here are the major changes:

  • To print a component for each page, a loop is created on state.pages. Within each <route></route>, the span HTML elements are used as Riot components by adding the is attribute:
<route each={ page in state.pages  } path={ page.path }>
   <span is={ page.component } route={ route }></span>
</route>
  • Navigation drawer links are also generated thanks to the route configuration, which is accessible with state.pages:
<template each={ page in state.pages }>
   <a href={ page.href }>
      <i>{ page.icon }</i>
      <span class="max">{ page.name }</span>
   </a>
   <div if={ page.separator === true } class="medium-divider"></div>
</template> 
  • The route object is used on the Javascript part to check if the current URL exists: A stream of routes is created to listen for route changes on the onMounted () {} Riot lifecycle. When a route changes, a function checks if the URL matches an existing route:
onMounted (props, state) {
  this.anyRouteStream = route('(.*)')
  this.anyRouteStream.on.value((path) => {
     this.update({ showNotFound: !this.state.pages.some(p => match(path.pathname, toRegexp(p?.path))) })  
  })
},
onUnmounted() {
  // When the component is unmounted, the stream is stopped.
  this.anyRouteStream.end()
}
  • For each component, the current route is passed as Props:
<span is={ r.component } route={ route }></span>

Within each component, the route is accessible with props.route, for instance the c-inbox.riot file:

<p-inbox>
    <h2> Inbox </h2>
    <span>Filter: { props.route.searchParams.get('filter') }</span><br>
    <span>Order By: { props.route.searchParams.get('order') }</span>
</p-inbox>

Now you can use query parameters to request an API when the page is loaded in the onMounted(){} Riot lifecycle.

Conclusion

Riot Route lets you create the navigation easily, with a syntax that is always close to HTML standards.

One limitation of a Single Page Application is that it depends on a Backend/API to load the data. The browser/user has to wait until the content is rendered. To counter this issue, you can render HTML on the server side with Riot-SSR: the first request receives the page filled with data, so the user won't have to wait.

Have a great day! Cheers 🍻

...

✅ RiotJS Routes


📈 43.71 Punkte

✅ Made typos in routes? Redirect routes with functions


📈 34.41 Punkte

✅ Next.js 14 Intercepting Routes with Dynamic Routes


📈 34.41 Punkte

✅ Implementing Photo Modal in Next JS using Parallel Routes & Intercepting Routes


📈 34.41 Punkte

✅ Laravel Wildcard Routes & Fallback Routes


📈 34.41 Punkte

✅ 🇫🇷 Utiliser RiotJS avec BeerCSS Material Design 3


📈 26.5 Punkte

✅ 🇫🇷 Base d'une application RiotJS avec Vite


📈 26.5 Punkte

✅ Stepper Component with RiotJS (Material Design)


📈 26.5 Punkte

✅ Menu Component with RiotJS (Material Design)


📈 26.5 Punkte

✅ Snackbar Component with RiotJS (Material Design)


📈 26.5 Punkte

✅ Search Component with RiotJS (Material Design)


📈 26.5 Punkte

✅ Dialog Component with RiotJS (Material Design)


📈 26.5 Punkte

✅ Tabs Component with RiotJS (Material Design)


📈 26.5 Punkte

✅ RiotJS + ViteJS tutorial


📈 26.5 Punkte

✅ 🇫🇷 Input Component avec RiotJS


📈 26.5 Punkte

✅ On the third day of Enhancing: API routes and the Store


📈 17.21 Punkte

✅ Create API Routes Using Next Js


📈 17.21 Punkte

✅ Group routes according to the categories and apply different layouts with layout.tsx in NextJs App Routing.


📈 17.21 Punkte

✅ GPS Tracks 1.6.6 - Create and edit routes.


📈 17.21 Punkte

✅ Gogs 0.11.86 Permission Check routes/api/v1/api.go privilege escalation


📈 17.21 Punkte

✅ What's New in API7 Enterprise 3.2.12: Supporting Stream Routes


📈 17.21 Punkte

✅ How to Create User Routes in Node.js: A Step-by-Step Guide


📈 17.21 Punkte

✅ Navigating new routes, places and distance: Introducing Google Maps Platform to Dev Library


📈 17.21 Punkte

✅ Satellites Could Show Airplanes Faster Long-Haul Routes in Mid-Air


📈 17.21 Punkte

✅ 89-Nodejs Course 2023: Restful Routes: Introduction


📈 17.21 Punkte

✅ CVE-2024-39173 | calculator-boilerplate 1.0 /routes/calculator.js eval input injection


📈 17.21 Punkte

✅ How to Use Typed Routes in Next.js


📈 17.21 Punkte

✅ React Firebase Auth Template (With Protected Routes)


📈 17.21 Punkte

✅ Obfuscating your create react app and routes


📈 17.21 Punkte

✅ Display External User Avatars Using Strapi's Custom Routes as a Proxy


📈 17.21 Punkte

✅ Simplifying Nested Routes in React Router


📈 17.21 Punkte

✅ Diablo 4: All Altar of Lilith locations, statue maps, and fastest routes


📈 17.21 Punkte

✅ Enhance API Routes and OpenAPI


📈 17.21 Punkte

✅ Privacy of fitness tracking apps in the spotlight after soldiers’ exercise routes shared online


📈 17.21 Punkte











matomo

Datei nicht gefunden!