HyperRouter
 HyperRouter is a DSL wrapper for ReactRouter v4.x to provide client-side routing for Single Page Applications (SPA). As the user changes "pages" instead of reloading from the server your App will mount different components.
This Page Under Construction
Usage
class AppRouter
  include Hyperstack::Component
  include Hyperstack::Router::Helpers
  include Hyperstack::Router
  render(DIV) do
    UL do
      LI { Link('/') { 'Home' } }
      LI { Link('/about') { 'About' } }
    end
    Route('/', exact: true, mounts: Home)
    Route('/about', mounts: About)
  end
end
class Home
  include Hyperstack::Component
  render(DIV) do
    H2 { 'Home' }
  end
endDSL
Router
This is the Router module which you include in your top level component:
class MyRouter
  include Hyperstack::Component
  include Hyperstack::Router
endWith the base Router class, you can also specify the history you want to use.
This can be done either using a macro:
class MyRouter
  include Hyperstack::Component
  include Hyperstack::Router
  history :browser  # this is the default option if no other is specified
endThe macro accepts three options: :browser, :hash, or :memory.
Or by defining the history method:
class MyRouter
  include Hyperstack::Component
  include Hyperstack::Router
  def history
    self.class.browser_history
  end
endRendering a Router
Use the render macro as normal. Note you cannot redefine the render instance method in a Router componenent
class MyRouter
  ...
  render(DIV) do
    H1 { 'Hello world!' }
  end
endRoutes
Routes are defined with special pseudo components you call inside the router/components. The router determines which of the routes to actually mount based on the current URL.
class MyRouter
  ...
  render(DIV) do
    Route('/', mounts: HelloWorld)
  end
end
class HelloWorld
  render do
    H1 { 'Hello world!' }
  end
endThe Route method takes a url path, and these options:
mounts: ComponentThe component you want to mount when routed toexact: BooleanWhen true, the path must match the location exactlystrict: BooleanWhen true, the path will only match if the location and path both have/don't have a trailing slash
The Route method can also take a block instead of the mounts option.
class MyRouter
  ...
  render(DIV) do
    Route('/', exact: true) do
      H1 { 'Hello world!' }
    end
  end
endThe block will be given the match, location, and history data:
class MyRouter
  ...
  render(DIV) do
    Route('/:name') do |match, location, history|
      H1 { "Hello #{match.params[:name]} from #{location.pathname}, click me to go back!" }
        .on(:click) { history.go_back }
    end
  end
endThe
Hyperstack::Router::Helpersis useful for components mounted by the router.This automatically sets the
match,location, andhistoryparams,and also gives you instance methods with those names.
You can use either
params.matchor justmatch.and gives you access to the
Routemethod and more.This allows you to create inner routes as you need them.
class MyRouter
  include Hyperstack::Component
  include Hyperstack::Router::Helpers
  include Hyperstack::Router
  render(DIV) do
    Route('/:name', mounts: Greet)
  end
end
class Greet
  include Hyperstack::Component
  include Hyperstack::Router::Helpers
  render(DIV) do
    H1 { "Hello #{match.params[:foo]}!" }
    Route(match.url, exact: true) do
      H2 { 'What would you like to do?' }
    end
    Route("#{match.url}/:activity", mounts: Activity)
  end
end
class Activity
  include Hyperstack::Component
  include Hyperstack::Router::Helpers
  include Hyperstack::Router
  render(DIV) do
    H2 { params.match.params[:activity] }
  end
endNormally routes will always render alongside sibling routes that match as well.
class MyRouter
  ...
  render(DIV) do
    Route('/goodbye', mounts: Goodbye)
    Route('/:name', mounts: Greet)
  end
endSwitch
Going to /goodbye would match /:name as well and render Greet with the name param with the value 'goodbye'. To avoid this behavior and only render one matching route at a time, use a Switch component.
class MyRouter
  ...
  render(DIV) do
    Switch do
      Route('/goodbye', mounts: Goodbye)
      Route('/:name', mounts: Greet)
    end
  end
endNow, going to /goodbye would match the Goodbye route first and only render that component.
Links
Links are provided by both the Hyperstack::Router and Hyperstack::Router::Helper modules.
The Link method takes a url path, and these options:
search: Stringadds the specified string to the search queryhash: Stringadds the specified string to the hash locationit can also take a block of children to render inside it.
class MyRouter
  ...
  render(DIV) do
    Link('/Gregor Clegane')
    Route('/', exact: true) { H1() }
    Route('/:name') do |match|
      H1 { "Will #{match.params[:name]} eat all the chickens?" }
    end
  end
endNavLinks
NavLinks are the same as Links, but will add styling attributes when it matches the current url
active_class: Stringadds the class to the link when the url matchesactive_style: Stringadds the style to the link when the url matchesactive: ProcA proc that will add extra logic to determine if the link is active
class MyRouter
  ...
  render(DIV) do
    NavLink('/Gregor Clegane', active_class: 'active-link')
    NavLink('/Rodrik Cassel', active_style: { color: 'grey' })
    NavLink('/Oberyn Martell',
            active: ->(match, location) {
              match && match.params[:name] && match.params[:name] =~ /Martell/
            })
    Route('/', exact: true) { H1() }
    Route('/:name') do |match|
      H1 { "Will #{match.params[:name]} eat all the chickens?" }
    end
  end
endPre-rendering
Pre-rendering is automatically taken care for you under the hood.
Setup
To setup HyperRouter:
Install the gem
Your page should render your router as its top-level-component (first component to be rendered on the page) - in the example below this would be
AppRouterYou will need to configure your server to route all unknown routes to the client-side router (Rails example below)
With Rails
Assuming your router is called AppRouter, add the following to your routes.rb
root 'Hyperstack#AppRouter' # see note below
match '*all', to: 'Hyperstack#AppRouter', via: [:get] # this should be the last line of routes.rbNote:
root 'Hyperstack#AppRouter' is shorthand which will automagically create a Controller, View and launch AppRouter as the top-level Component. If you are rendering your Component via your own COntroller or View then ignore this line.
Example
Here is the basic JSX example that is used on the react-router site
import React from 'react'
import {
  BrowserRouter as Router,
  Route,
  Link
} from 'react-router-dom'
const BasicExample = () => (
  <Router>
    <div>
      <ul>
        <li><Link to="/">Home</Link></li>
        <li><Link to="/about">About</Link></li>
        <li><Link to="/topics">Topics</Link></li>
      </ul>
      <hr/>
      <Route exact path="/" component={Home}/>
      <Route path="/about" component={About}/>
      <Route path="/topics" component={Topics}/>
    </div>
  </Router>
)
const Home = () => (
  <div>
    <h2>Home</h2>
  </div>
)
const About = () => (
  <div>
    <h2>About</h2>
  </div>
)
const Topics = ({ match }) => (
  <div>
    <h2>Topics</h2>
    <ul>
      <li><Link to={`${match.url}/rendering`}>Rendering with React</Link></li>
      <li><Link to={`${match.url}/components`}>Components</Link></li>
      <li><Link to={`${match.url}/props-v-state`}>Props v. State</Link></li>
    </ul>
    <Route path={`${match.url}/:topicId`} component={Topic}/>
    <Route exact path={match.url} render={() => (
      <h3>Please select a topic.</h3>
    )}/>
  </div>
)
const Topic = ({ match }) => (
  <div>
    <h3>{match.params.topicId}</h3>
  </div>
)
export default BasicExampleAnd here is the same example in Hyperstack:
class BasicExample
  include Hyperstack::Component
  include Hyperstack::Router::Helpers
  include Hyperstack::Router
  render(DIV) do
    UL do
      LI { Link('/') { 'Home' } }
      LI { Link('/about') { 'About' } }
      LI { Link('/topics') { 'Topics' } }
    end
    Route('/', exact: true, mounts: Home)
    Route('/about', mounts: About)
    Route('/topics', mounts: Topics)
  end
end
class Home
  include Hyperstack::Component
  include Hyperstack::Router::Helpers
  render(DIV) do
    H2 { 'Home' }
  end
end
class About  
  include Hyperstack::Component
  include Hyperstack::Router::Helpers
  render(:div) do
    H2 { 'About' }
  end
end
class Topics
  include Hyperstack::Component
  include Hyperstack::Router::Helpers
  render(DIV) do
    H2 { 'Topics' }
    UL() do
      LI { Link("#{match.url}/rendering") { 'Rendering with React' } }
      LI { Link("#{match.url}/components") { 'Components' } }
      LI { Link("#{match.url}/props-v-state") { 'Props v. State' } }
    end
    Route("#{match.url}/:topic_id", mounts: Topic)
    Route(match.url, exact: true) do
      H3 { 'Please select a topic.' }
    end
  end
end
class Topic
  include Hyperstack::Component
  include Hyperstack::Router::Helpers
  render(:div) do
    H3 { match.params[:topic_id] }
  end
endLast updated
Was this helpful?