View framework agnostic react-router-redux :)
- Make your Stateless component based development flow easy. work with these libraries.
- âś…React
- âś…vidom
- âś…snabbdom
- Should also work with other vdom libraries(https://github.com/Matt-Esch/virtual-dom)
- Adds pushState/popState based client-side routing to your project.
- Light weight(around 7K) but yet powerful router for Redux.
Demo: http://subuta.github.io/router-redux/
npm install router-redux --save
First you need to pass routerReducer to your own reducer with routing key.
// In reducers/index.js
import {combineReducers} from 'redux';
import {routerReducer} from 'router-redux';
const rootReducer = combineReducers({
routing: routerReducer // HERE
});
export default rootReducer;Next you need to pass routerMiddleware to your createStore function.
Then create and export router.
// In example/store.js
import createRouter, {routerMiddleware} from 'router-redux';
import reducer from './reducers/index.js';
const middlewares = [routerMiddleware];
const store = createStore(reducer, compose(
applyMiddleware(...middlewares)
));
export const router = createRouter(store);Then router enables you to pushState/popState based routing with redux.
// Get your exported router
import {router} from 'example/store.js';}
// Get router selector from router-redux
import {
getRouteError
} from 'router-redux';
// Register onError first (if you need to catch routing error)
router.onError(({state, dispatch}) => {
const routeError = getRouteError(state); // will extract error message from state.
console.log('routeError.message = ', routeError.message);
router.push('/error');
// You can navigate user to error page or call any other redux action.
dispatch(push('/error'));
});
// Called when user entered to path(/)
const onEnter = ({state}, cb) => {
console.log('[top]loading ...', state);
setTimeout(() => {
// User's navigation action will blocked untill `cb` called.
console.log('[top]timer fired');
cb();
// If you call `cb` with falsy value or Error object,
// Router-redux will emit router's onError. and stop routing to path(/).
// cb(new Error('[top]thrown error'));
}, 1000);
};
// Called when user leave from path(/)
const onLeave = ({state}) => {
console.log('[top]leave');
};
// Simple component to render.
const Top = () => {
return <h1>top</h1>;
};
router.on('/', <Top onEnter={onEnter} onLeave={onLeave}/>)see example/components for full example.
/react-> example of React with JSX plugin./vidom-> example of vidom plugin./snabbdom-> example of snabbdom- other files are common redux files(
actions/reducers/store)
- API idea came from react-router-redux thanks!
router-redux's middleware function for redux.
You need to register it in your createStore function.
// In store.js
import createRouter, {routerMiddleware} from 'router-redux';
import reducer from './reducers/index.js';
const middlewares = [routerMiddleware];
const store = createStore(reducer, compose(
applyMiddleware(...middlewares)
));
export const router = createRouter(store);router-redux's reducer function for redux.
You need to register it in your combineReducers function.
// In reducers/index.js
import {combineReducers} from 'redux';
import {routerReducer} from 'router-redux';
const rootReducer = combineReducers({
routing: routerReducer // here
});
export default rootReducer;When you import router-redux, it gives you createRouter,
You need to pass store to routerCreator, and it returns router for later use.
export const router = createRouter(store)
Optionally you can pass history to createRouter like below.
import createHistory from 'history/createBrowserHistory'
const history = createHistory({basename: '/router-redux'});
export const router = createRouter(store, {history})
Will created by routerCreator above.
router will handle these basic router operation.
- register your render/onEnter/onLeave function to the router using
router.on(path, handler) - navigate to other route using
router.pushand other history API based actionreplace/go/back/forward
- will register your render function to router.
pathcan includespath parameterlike (/foo/:id) andpathcan be '*'(wildcard) for default route.handlerwill accepts these value.router.on(path, {render, onEnter, onLeave})-> is formal syntax.router.on(path, <Component onEnter={onEnter} onLeave={onLeave}/>)-> is jsx version of formal syntaxrouter.on(path, fn)-> will call passed function asrenderfunction.
- if current location matches passed
paththenrouter.onwill call passedonEnteras initial route.
- If you specify
path parameterto path,router-reduxwill setrouteandparamsproperties inrouteobject(please referselectorssection). handler({state, dispatch}, [callback])- Called when user navigated to
pathby pushState/popState or directly(by browser's url bar) - Handler will block routing until
callbackfunction is called. (This is useful for Authentication or Load page related data via ajax) - If you call
callbackfunction with falsy value(or Error object).router-reduxwill callrouter.onErrorand cancel navigation. (this is useful for handling un-authorized response or Server error) - If you omit
callbackfunction then your onEnter result will not affect to further navigation(become asynchronous). - If you navigate to
/foo/1from/, your state.routing inonEnterfunction will looks like below.
| Key | Value |
|---|---|
| current | current route (/) |
| next | next route (/foo/1) |
| last | previous route |
handler({state, dispatch})- Called when user navigated from
pathby pushState/popState - onLeave is called only user navigated from
pathafterinitialRouteResolved, it means you need to bindonEntercallback to use onLeave. - If you navigate to
/foo/1from/, Yourstate.routinginonLeavefunction will looks like below.
| Key | Value |
|---|---|
| current | current route (/) |
| next | null |
| last | previous route |
handler({state, dispatch})- Called when routeError occurred in
router.onEnter - You can get actual routeError using
getRouteErrorselector.
router.render()- After register your routes using
router.on(path, handler)you need to callrouter.renderto render component based on current route(location). - if not route matches current location then router will render
*route as a default route.
import {
inject,
router
} from 'example/store.js'
import {
getIsLoading
} from 'router-redux';
router.on('/', <Top onEnter={onEnter} onLeave={onLeave}/>)
const render = inject(({state}) => {
if (getIsLoading(state)) {
return <h1>loading ...</h1>
}
return router.render();
});- Create push/replace internal action with
path. - When you call push/replace action. router'redux will call pushState/replaceState of history API
- Create go/back/forward internal action.
- When you dispatch go/back/forward action. router'redux will call go/back/forward of history API
- Will extracts value from your state. You can use selectors with reselect if you like.
routehas these properties- pathname(
String):/foo/1 // path - search(
String):sample=true // Query param. you can use third-party library(https://github.com/ljharb/qs) to parse query. - params(
Object):{id: 1} // Matched params(declared in onEnter) - route(
String):/foo/:id // Matched route(declared in onEnter)
- pathname(
- Extracts
current routefromstate
- Extracts
last routefromstate
- Extracts
next routefromstate
- Extracts
routeErrorfromstate routeErrorbecometrueorError(truthy value) when you call onEnter handler'scallbackwith falsy value or Error object.
- Extracts
isLoadingfromstate isLoadingbecometrueafter onEnter called and until onEnter resolved(by callcb).- This is useful to implement page loading animation.
git clone https://github.com/subuta/router-redux
cd ./router-redux
- Caddy (Web server for Development)
- jspm@beta (For package management/build)
brew install caddy
npm install jspm@beta -g
npm i
jspm i
caddy
# Open link.
open http://localhost:3000