npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

redux-unity-router

v1.6.1

Published

Redux router that syncs history with store

Downloads

39

Readme

Redux Unity Router

Travis-CI Coverage Status npm version Scrutinizer Deps Deps-Dev Dependency Status

Simple routing for your redux application.

The main purpose of this router is to mirror your browser history to the redux store and help you easily declare routes.

We also provide React bindings!

Table of Contents

Installation

Install redux-unity-router package from npm:

npm i --save redux-unity-router

Usage

Before proceeding to the next step, we suggest you create a file containing your routes:

/* routes.js */

export default {
    id: 'Main',
    pattern: '/application/',
    data: {
        pageTitle: 'My simple application'
    },
    routes: [
        {
            id: 'News',
            pattern: '/news/',
            data: {
               pageTitle: 'My news'
            },
            routes: [
                {
                    id: 'Item',
                    pattern: ':id'
                }
            ]
        },
        {
            id: 'Contacts',
            pattern: '/contacts/'
        }
    ]
};

You can learn more about setting up routes and their structure in the API section.

Then require those routes and set up your store like this:

/* store.js */

import { createStore, applyMiddleware, compose, combineReducers } from 'redux';

// Previously defined routes
import routes from './routes.js';

import { createRouter, History } from 'redux-unity-router';

// Create history
const history = History.createBrowserHistory();

// Create router instance
const router = createRouter({ history, routes });

// Add router middleware to your list of middlewares
const middleware = [ router.middleware ];

// Enhance your store by using router's enhancer
const toEnhance = [
    router.enhancer,
    applyMiddleware(...middleware)
];

// Put it all together
const enhancer = compose(...toEnhance);
const reducers = combineReducers({
    router: router.reducer
});

const initialState = {}

const store = createStore(reducers, initialState, enhancer);

export default store;

Now you've got yourself a simple routing system!

After navigating to /news/1?edit=true#title you can expect your store's state to contain 'router' entry similar to:

{
    "pathname": "/news",
    "search": "?edit=true",
    "hash": "#title",
    "key": "gmj9fs",
    "query": {"edit": "true"},
    "state": {},
    "path": "/news/1?edit=true",
    "route": {
        "pattern": {"path": "/news/:id"},
        "id": "Item",
        "idPath": "News:Item",
        "params": {"id": "1"},
        "data": {"pageTitle": "My news"}
    }
}

You can manage your layout by using <RouterProvider>, <Fragment> and <Link> React-components. They should help keep your application simple and maintainable.

API

createRouter({ history, routes, immutable, slice })

import { createRouter } from 'redux-unity-router'

Router factory, that returns an instance of the router object, containing: middleware, enhancer and reducer.

history {Object}

History object created by abstraction over browser's History API.

routes {Array}

An array of routes. If any of the routes can be matched to the same pattern, the route that has been declared first in routes array will take precedence.

immutable {Boolean} optional

Default: false

If you use immutable store, set this to true.

slice {String} optional

Default: 'router'

Store's key, that will contain router's data.

route {Object}

An object containing route's definition.

pattern {Object|String}

Redux-Unity-Router uses path-to-regexp for route-matching. There's also a handy tool to test your patterns.

Although you can declare patterns in the form of strings, that becomes problematic, when you want to match a route with query parameters, that may appear in arbitrary order. For this situation you may want to declare a pattern in a form of a plain object:

path {String} optional

Same as you'd declare a pattern in a form of a string.

query {Object} optional

Plain query object.

id {String} optional (but recommended)

Default: equals pattern if typeof pattern === 'string' or pattern.path if typeof pattern === 'object'

Unique Id of the route. It is recommended that you define route's id, so you can easily navigate to it with <Link> component.

data {Object}

Any arbitrary data you want reflected in the redux store, when the route is matched.

routes {Array} optional

Any sub-routes a route may have. All the patterns and data of these sub-routes will be merged with their parent's . Sub-routes always take precedence over their parents in the matching process.

Example:

const routes = [
            {
                id: 'User',
                pattern: '/user/:id',
                data: {
                  pageTitle: 'User Profile'
                }
                routes: [
                    {
                        id: 'UserEdit',
                        data: {
                          pageTitle: 'Edit User Profile'
                        },
                        pattern: {
                            query: {
                                edit: 'true'
                            }
                        }
                    },
                    {
                        id: 'UserLogout',
                        data: {
                          message: 'goodbye'
                        },
                
                        pattern: {
                            path: 'logout'
                        }
                    }
                ]
            }
        ]

// This will produce 3 patterns:
// { path: '/user/:id', query: { edit: 'true' }, data: { pageTitle: 'User Profile' } }
// { path: '/user/:id/logout', data: { pageTitle: 'Edit User Profile' } }
// { path: '/user/:id', data: { pageTitle: 'User Profile', message: ''goodbye' } }

actions

import { actions } from 'redux-unity-router'

or

import actions from 'redux-unity-router/actions'

Actually, these are action-creators (functions, that produce plain action objects). You can use them if you want to programmatically navigate to any part of your application. Most of them correspond to standard methods of browser's History API (except for goToRoute and locationChange).

push(payload)

Navigate to new url/path.

payload {String|Object}

  • payload of type string will be interpreted as path or url.
  • payload of type object should contain one the following properties:
pathname {String} optional

e.g. '/news'

search {String} optional

e.g. '?edit=true'

hash {String} optional

e.g. '#title'

silent {Boolean} optional

Default: false

This extra option allows you to change current location url without propagating changes to the Redux store.

replace(payload)

Navigate to new url/path, replacing current history entry.

payload {String/Object}

Same as for push action.

go(payload)

Go back or forward in history stack.

payload {Integer}

e.g. -1

goBack()

Equivalent to go(-1).

goForward()

Equivalent to go(1).

goToRoute(payload)

Navigate to the predefined route.

payload {Object}

id {String}

Valid route ID.

params {Object} optional

If our route contains parameters, you should provide them here.

query {Object} optional

Plain query object.

hash {String} optional

Hash for the resulting url.

Example:

If you've defined a route like this:

{
    id: 'Preferences',
    pattern: '/prefs/:action'
}

and you want to navigate to /prefs/edit?edit=true#title, you should dispatch an action like this:

store.dispatch(actions.goToRoute({
  id: 'Preferences', 
  params: { action: 'edit' }, 
  query: { edit: true }, 
  hash: 'title'
}));

locationChange(payload)

You most likely will never use this one, as it is used by Redux-Unity-Router internally to produce an entirely new router state.

payload {Object}

Check your store for this one!

actionTypes

import { actionTypes } from 'redux-unity-router'

or

import actionTypes from 'redux-unity-router/actionTypes'

Internally Redux-Unity-Router dispatches actions with following action-types

  • @@REDUX_UNITY_ROUTER/**LOCATION_CHANGED**
  • @@REDUX_UNITY_ROUTER/**PUSH**
  • @@REDUX_UNITY_ROUTER/**REPLACE**
  • @@REDUX_UNITY_ROUTER/**GO**
  • @@REDUX_UNITY_ROUTER/**GO_BACK**
  • @@REDUX_UNITY_ROUTER/**GO_FORWARD**
  • @@REDUX_UNITY_ROUTER/**GO_TO_ROUTE**

Keep in mind, that if you want to handle actions with these action-types in your reducers, all actions except for @@REDUX_UNITY_ROUTER/LOCATION_CHANGED will be swallowed by Redux-Unity-Router's middleware.

React components

Although you can easily manage application's layout based on the router's redux store data, we do provide some handy react components for you to use:

<RouterProvider>

Props

routes {Array}

An array of routes. We advice you use the same array for both createRouter and <RouterProvider>.

immutable {Boolean}

Default: false

If you use immutable store, set this to true.

slice {String} optional

Default: 'router'

Store's key, that will contain router's data. Use the same one you've used in createRouter setting up your store.

<Link>

Props

Supports all default <a> properties.

to {String|Object}

  • string type will be interpreted as path or url (external urls are supported as well)
  • object type can be interpreted 2 ways: if it has property id, it will be interpreted as route (see actions.goToRoute), otherwise it will be considered as a standard location object (see actions.push).

className {String} optional

Default: 'link'

className for the generated link.

activeClass {String} optional

Default: 'link__active'

className that will be added to the link if it matches current route.

target {String|Null} optional

Default: null

Target attribute.

activeMatch false|'exact'|'partial'|{RegExp} optional

Default: false

Dictates whether and how activeClass should be added to the link.

  • false - no current route matching at all. This is the default behavior.
  • 'exact' - link will receive its activeClass only if its pathname, query and hash match current route's.
  • 'partial' - link will receive its activeClass when current route's pathname begins with the pathname supplied to link.
  • '{RegExp}' - if you supply a regular expression, current route's entire path will be tested against it.

onClick {Function} optional

Default: undefined

Optional onClick callback, that will be fired before <Link> dispatches its navigation action. If this callback returns a {Promise}, <Link>'s navigation action will be fired, when the returned {Promise} resolves.

Example

// Navigates to /application 
<Link to="/application" activeMatch="exact">Main page</Link>

// Navigates to /application/news?id=1#comment-box
<Link to={{ pathname: '/application/news', query: { id: '1' }, hash: 'comment-box' }}>News</Link>

// if route is defined like { id: 'Settings', pattern: '/user/:userId' } navigates to /user/1?edit=true#title
<Link to={{ id: 'Settings', params: { userId: '1' }, query: { edit: true }, hash: '#title' }}></Link>

<Fragment>

Displays react components and other <Fragment>s based on current route.

Props

id {String}

Route's ID that you want a <Fragment> displayed on.

redirect {String|Object} optional

Redirect to path, url or route, when id is the last in the chain of nested <Fragment>'s ids.

See <Link>'s to prop.

component {React component} optional

You can pass react component to be used as a direct child of the <Fragment>.

Example

<Fragment id="Main">
    Main component for my application.

    <Fragment id="News">
        Component with my news list.
    </Fragment>

    <Fragment id="Gallery" component={Gallery} /> // imported <Gallery> react component

    <Fragment id="Contacts">
       <Fragment id="Map" component={Map} />  // imported <Map> react component
    </Fragment>
 
   <Fragment id="Redirect" redirect={{ id: 'Redirected' }} />
   <Fragment id="Redirected">
      You have been redirected here.
   </Fragment>

</Fragment>

Examples

We provide a basic example of working React app that you can dig into. Just clone this repo and run:

npm run build:examples

Contributing

  • Provide conventional commit messages by using npm run commit instead of git commit.
  • Core contributors: use GitHub's Rebase and merge as a default way of merging PRs.

License

MIT © AuRu