redux router (with bindings) / one route = one code
The main purpose of the lib is to have a full redux driven history API router that is fast and easy to use.
That's why we identify route by unique code
, and use this codes internally.
The lib was created to simplify our routes usages. This is done by matching an unique code
to a route (we never identify a route with its href
).
This lib allows us, via bindings, to use path
params and query
params, and context
informations on top of that.
context
informations are the data you are putting in route definitions, like "is this route public?"
So this lib aims to simplify the maintenance of your routes:
- We use unique route
code
to identify routes, meaning that if you change relatedhref
your code is not impacted - We describe routes as nested components
- We allow to put
context
informations into routes definition context
informations are copied from parent to children and can be overwritten, meaning that you can put aisPublic: false
flag on a parent (and only on a parent), and all your children will have thisisPublic: false
set.
This lib is mostly influenced by redux-little-router and our first hoc hoc-little-router.
packages | size | gziped |
---|---|---|
@k-redux-router/core |
||
@k-redux-router/react-redux |
||
@k-redux-router/react-k-ramel |
yarn add @k-redux-router/core path-to-regexp
- with react-redux:
yarn add @k-redux-router/react-redux
- with k-ramel:
yarn add @k-redux-router/react-k-ramel
// you define your routes in a plain object
export default {
'/': { // url are keys of your route
code: 'main', // your routes are defined by a code, this is **required**
public: true, // you can add custom properties
'/login': { // url is `/login`
code: 'login',
// all the properties from parent route are copied into children
// so /login is public: true :)
},
'/users': { // url is `/users`
code: 'users',
public: false, // you can override parent properties
'/:id': { // url is `/users/:id`
code: 'user',
// public is false since parent defined it to false
'/socials': { // url is `/users/:id/socials`
code: 'user-socials', // code are UNIQUES !!
}
}
}
}
}
import { actions } from '@k-redux-router/core'
// dispatch a `@@router/PUSH` with
// - the route code (user here)
// - paths params that are named (id === 2 here)
// - eventually query params (as an object)
actions.push('user', { id: '2' })
// dispatch a `@@router/REPLACE` with
// - the route code (user here)
// - paths params that are named (id === 2 here)
// - eventually query params (as an object)
actions.replace('user', { id: '2' })
// dispatch a `@@router/GO_BACK` with
// - eventually the number of steps (1 is default)
actions.goBack()
// dispatch a `@@router/GO_FORWARD` with
// - eventually the number of steps (1 is default)
actions.goForward()
import { selectors } from '@k-redux-router/core'
// by default selectors() will look at `state.ui.router`
// you can change where the routes are located (where the reducer is binded), giving a callback
// in this example the router is located to `state.path.to.router`
const decoratedSelectors = selectors(state => state.path.to.router)
// state could be
// - retrieved from `getState` of redux-thunk
// - retrieved from `state` of react-redux
// - injected by `select` of redux-sagas
// - etc
// here this is a mock up
const state = {
path: {
to: {
router: { /* mock up to illustrate */ }
}
}
}
// get the route defined by the code `user`
decoratedSelectors.getRoute('user')(state)
// get the result
decoratedSelectors.getResult(state)
// the current route code
decoratedSelectors.getCurrentCode(state)
// the current route
decoratedSelectors.getCurrentRoute(state)
// is the route found? (404 or not)
decoratedSelectors.isFound(state)
// get query and path params
decoratedSelectors.getParams(state)
// get all the path params
decoratedSelectors.getPathParams(state)
// get all the query params
decoratedSelectors.getQueryParams(state)
// get ONE path param by its name
decoratedSelectors.getPathParam('id')(state)
// get ONE query param by its name
decoratedSelectors.getQueryParam('token')(state)
// get ONE param (either result param, path param or query param)
// - if the result param exists, this is returned first
// - then if the state param exists this is returned second
// - query param comes at last
decoratedSelectors.getParam('id')(state)
with pure redux
import { createStore, applyMiddleware, combineReducers, compose } from 'redux'
import { router } from '@k-redux-router/core'
import routes from './routes' // your routes defined previously
// if you want redux-devtools ;-)
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
// create the router
// - by default the path is `state.ui.router`
// - here we override it to `state.path.to.router`
const router = createRouter(routes, { getState: state => state.path.to.router })
// create the redux store
const store = createStore(
combineReducers({
path: combineReducers({
to: combineReducer({
// 1. bind the reducer where you want
// here this is in to `state.path.to.router`
router: router.reducer,
}),
}),
}),
undefined,
// 2. add the middleware
composeEnhancers(applyMiddleware(router.middleware)),
)
// 3. init the router
// this one is used to init the current route by reading your URL
store.dispatch(router.init())
export default store
with k-ramel
import { createStore } from 'k-ramel'
import { router } from '@k-redux-router/react-k-ramel'
import routes from './routes' // your routes defined previously
// create the redux store
export default createStore(
{
ui: {},
},
{
drivers: {
// 1. add the driver (its name should be 'router')
router: router({
routes, // 2. bind your routes
state: 'path.to.router' // 3. the path to the state (default is `ui.router`)
getState: state => state.path.to.router // 4. accessor to the state (default is `ui.router`)
}),
},
},
)
At that time we only have binding for ReactJS
but feel free to add more if needed :)
You can use this library with either k-ramel or a raw redux application (with react-redux).
The API is quite the same, the import will change:
- k-ramel:
import { forRoute } from '@k-redux-router/react-k-ramel'
- react-redux:
import { forRoute } from '@k-redux-router/react-redux'
import { forRoute } from '@k-redux-router/react-k-ramel'
// or import { forRoute } from '@k-redux-router/react-redux'
// this is the wrapped component (to print _or not_ based on route)
import Component from './Component'
// this will print `Component` when the route identified by the `main` code is found
// -> if you are in a `second` route that is a child of `main`
// then Component will *NOT* be printed here
export default forRoute.absolute('main')(Component)
// this will print `Component` when the route identified by the `main` code is found
// in the tree
// -> if you are in a `second` route that is a child of `main`
// then Component *WILL* be printed here
export default forRoute('main')(Component)
// You can use simple route codes (single string) or an array in all the previous hoc
// Here we will print component if either `second` or `third` route is found
export default forRoute.absolute(['second', 'third'])(Component)
// this will print `Component` when no routes are found (you can handle client 404 here)
export default forRoute.notFound()(Component)
// if you don't use the default reducer location (ui.router), you can override it here (react-redux)
export default forRoute('main', { getState: state => state.custom.location })(Component)
import { Link } from '@k-redux-router/react-k-ramel'
// or import { Link } from '@k-redux-router/react-redux'
export default () => (
<div>
{/* link to the `second` route */}
<Link
code="second"
>
click here
</Link>
{/* link to the `user` route passing its `id` in path params */}
<Link
code="user"
id={3}
>
user detail
</Link>
{/* link to the `search` route passing query params */}
<Link
code="search"
query={{ max: 3, name: 'Jean' }}
>
search users that are named 'Jean'
</Link>
</div>
)
uni rakun is created by two passionate french developers.
Do you want to contact them? Go to their website
Guillaume CRESPEL | Fabien JUIF |