|
1 | 1 | # cyclic-router
|
2 |
| -Router Driver built for Cycle.js |
| 2 | +cyclic-router is a Router Driver built for Cycle.js |
3 | 3 |
|
4 |
| -Check out the example/ until I get some documentation together :smile: |
| 4 | +## Installation |
| 5 | + |
| 6 | +Using [npm](https://www.npmjs.com/): |
| 7 | + |
| 8 | + $ npm install cyclic-router |
| 9 | + |
| 10 | +Then with a module bundler like [browserify](http://browserify.org/), use as you would anything else: |
| 11 | + |
| 12 | +```js |
| 13 | +// using an ES6 transpiler, like babel |
| 14 | +import {makeRouterDriver} from 'cyclic-router' |
| 15 | + |
| 16 | +// not using an ES6 transpiler |
| 17 | +var makeRouterDriver = require('cyclic-router').makeRouterDriver |
| 18 | +``` |
| 19 | + |
| 20 | +## API |
| 21 | + |
| 22 | +Api docs comming real soon, please view `Getting started` below to have an understanding of how to implement cyclic-router into your own project. |
| 23 | + |
| 24 | + |
| 25 | +## Getting started |
| 26 | + |
| 27 | +###1. |
| 28 | + |
| 29 | +Here is a rundown of the `example` provided with this repo in the folder `/example`. This should allow a better understanding of how to use cyclic-router, for simplicity the styling has been removed here. |
| 30 | + |
| 31 | +Starting in the file which has Cycle `run`, router driver needs to be created here along with the other drivers that you might be using. |
| 32 | +Looking at the imports below, [cyclic-history](https://github.com/tylors/cyclic-history) is being used instead of cycle-history. |
| 33 | + |
| 34 | +```js |
| 35 | +// main.js |
| 36 | +import {run} from '@cycle/core' |
| 37 | +import {makeDOMDriver} from 'cycle-snabbdom' |
| 38 | +import {makeHistoryDriver} from 'cyclic-history' |
| 39 | +import {makeRouterDriver} from 'cyclic-router' |
| 40 | +import {createHashHistory} from 'history' |
| 41 | + |
| 42 | +import app from './app' // the function of your app |
| 43 | + |
| 44 | +run(app, { |
| 45 | + DOM: makeDOMDriver('#app'), |
| 46 | + // Notice how you need to feed in funcs from cyclic-history + history |
| 47 | + router: makeRouterDriver(makeHistoryDriver(createHashHistory())), |
| 48 | +}) |
| 49 | +``` |
| 50 | + |
| 51 | +In this instance we are using `cyclic-history` and `history` to deal with the history API, have a read of the history [docs](https://github.com/rackt/history/tree/master/docs#readme) to find out more information on how that all works. |
| 52 | + |
| 53 | +###2. |
| 54 | + |
| 55 | +App.js will be used as the place for showing the correct component in reference to current url (what you'd expect from a router!). |
| 56 | +When creating your `routes` object keep in mind that cyclic-router uses [switch-path](https://github.com/staltz/switch-path) and it is worth checking out that repo to understand the structure that `switch-path` expects. |
| 57 | + |
| 58 | +```js |
| 59 | +// app.js |
| 60 | +import {div, nav} from 'cycle-snabbdom' |
| 61 | + |
| 62 | +import Sidebar from './components/sidebar' |
| 63 | +import Home from './components/home' |
| 64 | +import Inbox from './components/inbox' |
| 65 | +import Compose from './components/compose' |
| 66 | +import NotFound from './components/notfound' |
| 67 | + |
| 68 | +// routes is used for matching a route to a component |
| 69 | +const routes = { |
| 70 | + '/': Home, |
| 71 | + '/inbox': Inbox, |
| 72 | + '/compose': Compose, |
| 73 | + '*': NotFound, |
| 74 | +} |
| 75 | + |
| 76 | +// the view has sidebar & children passed in |
| 77 | +function view(sidebar, children) { |
| 78 | + return div([ |
| 79 | + nav([sidebar]), |
| 80 | + div([children]), |
| 81 | + ]) |
| 82 | +} |
| 83 | + |
| 84 | +function App(sources) { |
| 85 | + const {router} = sources // get router out of sources |
| 86 | + const {path$, value$} = router.define(routes) // pass routes into the router |
| 87 | + const sidebar = Sidebar(sources, path$) // pass in sources and path$ into our sidebar |
| 88 | + |
| 89 | + // childrenDOM$ takes path$ from `router.define(routes)` above and zips it with values, here is where |
| 90 | + // the components swap in reference to the current url, notice router.path(path) is also passed in |
| 91 | + // for later use in nested routes. |
| 92 | + // This allows components to be nested without ever knowing they are actually nested. |
| 93 | + const childrenDOM$ = path$.zip(value$, |
| 94 | + (path, value) => value({...sources, router: router.path(path)}).DOM |
| 95 | + ) |
| 96 | + |
| 97 | + return { |
| 98 | + DOM: sidebar.DOM.combineLatest(childrenDOM$, view), |
| 99 | + } |
| 100 | +} |
| 101 | + |
| 102 | +export default App |
| 103 | +``` |
| 104 | + |
| 105 | + |
| 106 | +###3. |
| 107 | + |
| 108 | +Next, lets look at what triggers these url changes inside the sidebar |
| 109 | + |
| 110 | +```js |
| 111 | +// ./components/sidebar.js |
| 112 | +import {ul, li, a} from 'cycle-snabbdom' |
| 113 | + |
| 114 | +function Sidebar(sources, path$) { |
| 115 | + // take out createHref from our sources |
| 116 | + const {router: {createHref}} = sources |
| 117 | + |
| 118 | + // here the urls we want to use are passed into createHref. |
| 119 | + // createHref() will always create the proper href no matter how far it is nested within a hierarchy. |
| 120 | + const inboxHref = createHref('/inbox') |
| 121 | + const composeHref = createHref('/compose') |
| 122 | + const contactHref = createHref('/contact') |
| 123 | + |
| 124 | + // adding li's links and giving them Href's from above |
| 125 | + const view$ = path$.map(() => { |
| 126 | + return ul({style: ulStyle},[ |
| 127 | + li([a({props: {href: inboxHref}}, 'Inbox')]), |
| 128 | + li([a({props: {href: composeHref}}, 'Compose')]), |
| 129 | + li([a({props: {href: contactHref}}, 'Contacts')]), |
| 130 | + ]) |
| 131 | + }) |
| 132 | + |
| 133 | + return {DOM: view$} |
| 134 | +} |
| 135 | + |
| 136 | +export default Sidebar |
| 137 | +``` |
| 138 | + |
| 139 | +At this point you are at a good stage to be able to make a simple app/site with multiple pages. Next taking a look at nesting these routes directly within children components. |
| 140 | + |
| 141 | + |
| 142 | +###4. |
| 143 | + |
| 144 | +Nested routing becomes very trivial, as you can see below it is as simple as repeating the same steps as above. |
| 145 | + |
| 146 | +```js |
| 147 | +// ./components/inbox/index.js |
| 148 | +import {div, ul, li, a} from 'cycle-snabbdom' |
| 149 | + |
| 150 | +import Why from './why' |
| 151 | +import Compose from './compose' |
| 152 | +import Built from './built' |
| 153 | + |
| 154 | +const routes = { |
| 155 | + '*': () => ({DOM: div({style: {opacity: 0}})}), |
| 156 | + '/why': Why, |
| 157 | + '/built': Built, |
| 158 | + '/compose': Compose, |
| 159 | +} |
| 160 | + |
| 161 | +function view(createHref, path$, children) { |
| 162 | + return path$.map(() => { |
| 163 | + return div({},[ |
| 164 | + ul([ |
| 165 | + li([ |
| 166 | + a({props: {href: createHref('/why')}, |
| 167 | + }, 'Why Cyclic Router?'), |
| 168 | + ]), |
| 169 | + li([ |
| 170 | + a({props: {href: createHref('/built')}, |
| 171 | + }, 'Built For Cycle.js'), |
| 172 | + ]), |
| 173 | + li([ |
| 174 | + a({props: {href: createHref('/compose')}, |
| 175 | + }, 'Compose a Message'), |
| 176 | + ]), |
| 177 | + ]), |
| 178 | + children, |
| 179 | + ]) |
| 180 | + }) |
| 181 | +} |
| 182 | + |
| 183 | +function Inbox(sources) { |
| 184 | + const {router} = sources |
| 185 | + const {path$, value$} = router.define(routes) |
| 186 | + |
| 187 | + const childrenDOM$ = value$.map(value => value(sources).DOM) |
| 188 | + |
| 189 | + return {DOM: view(router.createHref, path$, childrenDOM$)} |
| 190 | +} |
| 191 | + |
| 192 | +export default Inbox |
| 193 | +``` |
0 commit comments