redux-tower
Saga powered routing engine for Redux apps.
redux-tower provides a way to fully control client-side routing with its related side effects such as data fetching, user authentication, fancy animations.
NOTICE: This package is ACTIVELY under development. API (both public and internal) may change suddenly.
Installation
npm install --save redux-tower
The Goal
- Integrated, Battery-included, but Replaceable
- Affinity with Redux
Why?
- react-router is just a component switcher. I don't want to depend on React component lifecycle.
- react-router-redux doesn't help you to do something before showing a page component.
- redux-saga brings long-running processes with async control flow to Redux.
About redux-saga-router
redux-saga-router is a great routing library, which brings sagas to the chaotic router world and gives a way to do side effects in redux-saga way when associated url is activated. However, it can't be used to control the timing of showing the page component and what component should be shown, because both react-router and redux-saga-router are working separately. I feel it annoying to maintain the separated route definitions.
Examples
Online Demo
- Minimum: Source | Demo | Minimum usage example with Hash based history.
- Blog: Source | Demo | Real World Blog app using Semantic UI React.
redux-logger is enabled. Open the JavaScript console of developer tools in your browser. You can also use Redux DevTools extension to see the store and the actions being fired.
Try in local
Clone this repository and run following npm commands.
npm install
npm start
And then open http://localhost:8080/
with your favorite browser.
Usage
Here is a SFA (Single File Application) that shows you a simple routing with side effects.
// Pages { return <ul> <li><a href='#/'>Index</a></li> <li><a href='#/tower'>Tower</a></li> </ul>;} { return <div> <h1>Index</h1> <Navigation /> <p>Hi here is index page</p> </div>; } { return <div> <h1>Tower</h1> <Navigation /> <p>Here is tower page You waited a while for loading this page</p> </div>; } // Routesconst routes = '/': Index *'/tower' ; Tower; ; // Historyconst history = ; // Saga { ;} // Reducerconst reducer = ; const sagaMiddleware = ;const store = ;sagaMiddleware; ReactDOM;
API / Building Blocks
redux-tower consists of several different kinds of elements/components. In this section, I'd like to introduce them step by step and how to integrate with your Redux application.
Routes
First of all, you need to have the route definition which contains URL patterns and route actions. The behavior of routing is deadly simple. When a url pattern is activated, the engine tests URL patterns, and pick a route action from your definition, and runs it. The difference with other routing libraries is that this is not a simple component switcher like react-router. You can write a route action includes async control flows and interactions with Redux naturally to fully control the process of routing thanks to redux-saga. For increasing readability and productivity, redux-tower allows you to use a shorthand notation for changing components and redirections. The URL pattern is a plain string, but is able to capture a part of URL and captured values are passed to a route action as named parameters.
;; const routes = // Initial action or component (Optional) INITIAL: Loading { // Do something, such as data fetching, authentication, etc. ; // Update Redux's state ; // Change component Home; // Shorthand } // Nested routes '/posts': // Receive query string like '/posts?q=keyword' // Use method syntax for route action *'/' query ; // Change component (not shorthand) ; // Receive named parameters like '/posts/1' { ; PostsShow; } // Redirect to '/posts' after saving { ; '/posts'; // Shorthand } // Redirect to '/posts/:id' with fixed parameter '/about': '/posts/2' // Shorthand (lazy redirection) // Change component // Assign React component directly (except Stateless Functional Components) '/contact': Contact // Default error page (Optional) ERROR: NotFound // Global cancel action (Optional) CANCEL: { ; };
Hooks
In the route definition, a route action can have the entering/leaving hooks that are ran before/after the main action. It's a bit tricky behavior because the both hooks have a different timing when they are executed.
const routes = // ... // Enable entering hook '/admin': { // Check logged-in or not if // Redirect to login page '/users/login'; } // Admin section '/': './dashboard' '/dashboard': AdminDashboard '/posts': // Enable leaving hook '/:id/edit': AdminPostsEdit { // Dirty check if // Prevent page transition false; } '/users': '/login': UsersLogin { ; '/'; } ;
History
redux-tower is built on history package so that you can choose a strategy from Hash based or History API.
// History API; // Or Hash based; // ... const history = ;
Saga
The core of routing engine, which mainly have two respnsibilities:
- Detects location changes from
history
instance, reflects location data to Redux's store, and triggers route actions - Watches history related Redux's actions and operates
history
instance
Since it's provided as a saga, what you have to do is just launching it using fork
effect in the root saga of your application.
Don't forget to pass the option when you fork. Here is a list of options.
- history: An instance of
createBrowserHistory()
orcreateHashHistory()
. - routes: A route definition that previously introduced.
- offset: [Optional] A offset path for
createBrowserHistory()
. No need to use forcreateHashHistory()
.
; // ... { ; // ...}
Reducer
A reducer is used to expose the location data to Redux's store.
- path: String. Path string, which is stripped a query string.
- params: Object. Named parameters, which is mapped with placeholders in route patterns.
/users/:id
with/users/1
gets{ id: '1' }
. - query: Object. Parsed query string.
/search?q=hoge
gets{ q: 'hoge' }
. - splats: Array. Unnamed parameters, which is splatted from placeholders in route patterns.
/posts/*/*
.
; // ... /* your reducers */ router ;
Actions
Since this library is made for Redux, all state transitions, including routing, are triggered by actions.
Core actions
CHANGE_COMPONENT
: switch to other component
History actions
PUSH
: pushes a new pathREPLACE
: repalces with a new pathGO
:GO_BACK
:GO_FORWARD
:
React components
These React components will help you for building an application. I'm happy to hear feature requests and merge your PRs if you feel it doesn't satisfy your needs.
<Router>
A simple component switcher, which is connected with Redux.
; // ... ReactDOM;
<Link>
<Link>
component helps you to put a link in your Redux application.
; // ... { return <div> <Link to='/'>Home</Link> <Link external to='https://github.com/kuy'>@kuy</Link> </div>; }
Acknowledgment
redux-tower has inspired by redux-saga-router. Big thanks to @jfairbank.
License
MIT
Author
Yuki Kodama / @kuy