Skip to content

Instantly share code, notes, and snippets.

@jonaskuske
Last active February 4, 2018 02:09
Show Gist options
  • Save jonaskuske/ad54386885a27d5a2c003965815b740d to your computer and use it in GitHub Desktop.
Save jonaskuske/ad54386885a27d5a2c003965815b740d to your computer and use it in GitHub Desktop.
Minimal hyperapp router

Minimal hyperapp router

1. Usage

Configure

Specify your routes with paths and corresponding components

const routes = [
  {
    path: '/',
    component: MainPage
  },
  ...
]

Output

Import RouterView whereever you want to render it and use it like you use a normal component

import { RouterView } from './router.example';

const App = props => (
  <div>
    <RouterView />
  </div>
);

Because RouterView is just a reference to your real component, you can pass along props like you normally would

<RouterView themeColor={state.themeColor} />

Navigate

Call router.push with one of your specified paths to update the view

import router from 'router.example';

<button onclick={() => router.push('/subpage')}> Navigate! </button>

2. Setup

  • Your app needs to have an action called updateRouterView that changes the state everytime it's called.
    The router module needs access to the actions so it's able to call updateRouterView.
    By changing the state we force hyperapp to update the view once RouterView is changed.
    It's a bit hacky, but it works :)
    See main.example.js for an example.

  • Run router.init() immediately after calling app(state, actions, Component, target) to start hyperapp.
    This matches the current URL to update the view and sets up a listener for clicks on the browser's native forwards and backwards buttons.

  • In order for the router to work, your server has to respond with your index.html no matter which URL is requested.
    If you can configure your server with a .htaccess file, you can simple put a .htaccess containing FallbackResource /index.html in your root directory.
    For webpack's dev server, add devServer: { historyApiFallback: true } to your webpack config.

3. Limitations

   This is just a really simple routing implementation, allowing you to
   associate different pages/components with URL paths to build a very basic Single Page Application.
   It does not handle query strings, aliases, dynamic route matching and all the other features advanced routers offer.

import { app } from 'hyperapp';
import router from 'router.example.js';
const state = {
routerUpdater: false // changing this makes hyperapp update the page, rendering the new RouterView
}
const actions = {
updateRouterView: () => state => ({routerUpdater: !state.routerUpdater})
}
export default app(state, actions, YourStartComponent, document.body);
router.init();
import actions from 'main.example.js';
import Component1 from '...';
import Component2 from '...';
let RouterView;
const routes = [
{
path: '/',
component: Component1
},
{
path: '/subpage',
component: Component2
}
]
const router = {
push(path, pushState = true) {
RouterView = router.match(path);
actions.updateRouterView(); // see main.example.js
if (pushState) history.pushState({path}, path, path);
},
match(path) {
// returns Component associated with the matching route
// if no route matches, returns component far on the right (here Component1)
return routes.reduce((a, b) => b.path === path ? : b.component : a, Component1);
},
init() {
// call immediately after running app(...) to start hyperapp
// checks URL and updates page so you can navigate directly to http://url.com/subpage
// listens for popstate event and updates view so browsers' 🡨 and 🡪 buttons work
RouterView = router.match(window.location.pathname);
window.addEventListener('popstate', history => router.push(history.state.path, false));
}
}
export { RouterView };
export default router;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment