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

react-router-maa

v2.0.7

Published

state based react router linked to url through parseUrl and toUrl functions, has working route blocking control mechanisim, and async initialisation phase

Downloads

45

Readme

Build Status Coverage Status

Router Overview

State based router for react (and others not explicit to react). The idea is simple I want the url of the site to be linked to a state object. To do so the user supplies the router with a parseUrl and a toUrl function. And changing the url is done by changing the state object.

The router has a built in async (by returning a promise) initialisation phase which can be utilised by supplying the initializeRouter the initializationHandler parameter which if it return a state or a url(string) will set the initial url of the site (if it returns falsey value the initial url will not change). Note you can return a promise for async functionality. This is important for example if the initial url is say /user/:userId and you want to get the user info from the server and if no user is available with set id u want to redirect to another page say /home.

The router provides out of the box a working async route blocking mechanism available through pushTransitionAllowedCheckFunction. Where you add a function to be called before route is changed and if this function returns false the route will not change (utilise promises for async operation).

The state of the router is saved internally inside the router. To hook it to your react app use something like bellow which is specific to redux (full example here):

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import rootReducer from './reducers';
import './index.css';
import App from './components/App';
import { changeRouterState, initRouter } from './actions';
import { initializeRouter } from 'react-router-maa';
import { parseUrl, toUrl } from './utils';

const store = createStore(rootReducer);

initializeRouter(parseUrl, toUrl, null, (state, position, isInit) => {
  store.dispatch(changeRouterState(state, position, isInit));
}, (initState) => {
  return new Promise((resolve) => {
    store.dispatch(initRouter(initState, resolve));
  });
});

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>, 
  document.getElementById('root')
);

Example

I created a small app to demonstrate the router in action check example here.

I highly recommend checking the example as it helps demonstrate the power of this router in real world senarios. Even if you dont download and run the example locally checking the readme of the example is useful also.

API

initializeRouter(parseUrlFunction, toUrlFunction, mergeRouterStateChangeFunction, routerStateChangedHandler, initializationHandler, initializationTimeoutDuration = 10000, baseUrl='', initialNoneUrlState = {}, historyType = 'browser')

parseUrlFunction(url: string)

a function that takes in a url string and returns a state object.

toUrlFunction(state: Object)

a function that takes in a state object and returns a url string.

mergeRouterStateChangeFunction(state: Object, change: Object)

a function that takes in a state object and (state) change object and returns the new state (dont mutate state or else). send it as null (or falsey in general) to use Object.assign. in most cases you'll just send this as null.

routerStateChangedHandler(newState: Object, stateLocation: integer[, isInit: Boolean])

a function to be called every time the router state changed it will be given the newState as first argument, the stateLocation as the second (think of stateLocation as position in the states objects the current state is. when the site first load stateLocation is 0 if you push a new state it becomes 1), and isInit as the third argument this is set to true when the first state is set.

initializationHandler(initialState: Object)

a function that will be called upon initialization of the router. It will be supplied the initial state which is parsed from the initial url (window.location.pathname or window.location.hash) and merged with initialNoneUrlState(another argument). If this function returns an object it will be used as the initialState instead and the url changed accordingly (using the toUrl function) or if it returns a string it will be used as as the initial url and the initial state will be parsed from it (using the parseUrl function).

initializationTimeoutDuration: integer (ms) default 10 seconds

The duration in milliseconds to wait before timing out the initialisation function. Set to zero (or falsey in general) to disable the timeout.

baseUrl: string default empty string ('')

This will be passed as basename to the history object. It represents the base part of the url of your site which will be prefixed for all urls.

initialNoneUrlState: Object default empty object

The initial part of the state that is not stored in the url. Will be merged with the state parsed from the url initially to get the initialState. In most cases you will not need this. so keep it as the default.

historyType: string default 'browser'

Can be set to either 'browser', 'hash', 'memory', or 'hash-maa' selects the underlying history create function to be used. note 'hash-maa' is inspired by this comment, it uses internaly browser history but it abstracts this from the user.

isInitialised(): Boolean

@returns: Boolean

Returns whether or not the router is initialised.

pushRouterState(newState[, locationState]): Promise<Object|Boolean>

a function that pushes a new state to the router and changes the url accordingly.

newState: Object

The new state to push.

locationState: Object

will be forwarded to history.push as the second argument. Mostly you wont need this so dont send it.

@returns: Promise

Returns a promise that resolved to the new state if the navigation was not blocked, or a promise that resolves to explicitly false if the navigation was blocked.

pushRouterStateThroughChange(change[, locationState]): Promise<Object|Boolean>

a function that pushes a change to the current the router state and changes the url accordingly. The change object is merged with the current state using the mergeRouterStateChangeFunction(which defaults to Object.assign).

change: Object

The change object to merge with the current state.

locationState: Object

will be forwarded to history.push as the second argument. Mostly you wont need this so dont send it.

@returns: Promise

Returns a promise that resolved to the new state if the navigation was not blocked, or a promise that resolves to explicitly false if the navigation was blocked.

replaceRouterState(newState[, locationState]): Promise<Object|Boolean>

Same as pushRouterState but replaces current state instead of pushing new one.

replaceRouterStateThroughChange(change[, locationState]): Promise<Object|Boolean>

Same as pushRouterStateThroughChange but replaces current state instead of pushing new one.

goInRouterStates(delta: integer)

Goes back or forward in router states.

delta: integer

The change to move. -1 to go back one step, 1 to move forward one step. 0 will throw an error.

getRouterState([delta: integer])

Returns the router state delta steps away (same concept of delta in goInRouterStates above). Not sending a delta or sending a zero as delta will return the current state, which is what is needed in most cases.

delta: integer

-1 returns previous state, 1 returns next (forward) state. 0 or nothing will return the current state.

@returns: Object|undefined

Returns a the state at delta offset from current or undefined if it doesnt exist.

getRouterStateLocation(): integer

Returns current stateLocation

@returns: integer

Returns current stateLocation same as the one sent to routerStateChangedHandler explained above.

getRouterStateLength(): integer

Returns length of the states object.

@returns: integer

Returns length of the states object. E.g. if you navigated 10 times this will be 10.

pushTransitionAllowedCheckFunction(checkFunc, popOnceRouteAllowed = true, priority = 0, popCheckFunc = undefined): Function

pushes a transition allowed check function in order of priority.

checkFunc: Function

A function to be called to check if transition is to be allowed or not returning true will immitiately allow transition returning false will immidiately block transition returning undefined (like dont care) will keep checking other check functions on the stack. note: this function can be async i.e. returning a promise that resolves to true, false or undefined has the same effect as above but will be awited for. Also note that by default when a route is allowed the function will be poped (removed from the check call stack), to disable this behaviour send popOnceRouteAllowed (the second argument) as false. This is done specifically like this cause most of the time you push a function for example at pageLoad/componentDidLoad to block transition if some changes have not been saved and once the user confirms or there is no changes anyways, you want the check function to be removed. NOTE: the check function will be called with one argument of the following format:

  {
    state,    // the current state
    newState, // the tentative next state
    action,   // 'POP', 'PUSH' or 'REPLACE' as in the [history](https://github.com/ReactTraining/history) package
    popMe     // a function if called will pop the check regardless if route is allowed or not
  }

popOnceRouteAllowed: Boolean default true

If set to false will not remove the checkFunction when transition is allowed. See argument in checkFunc description above.

priority: Number default 0

The priority of this check. Bigger priorities will be called first. I used this for example in the case of a form where you want to block the transition if there is unsaved changes but for some reason the server returns a 401 error and you need to redirect to login page. To do so here just add the 401 check with higher priority and only return true if the the nextState is for the login page and the action is not POP. NOTE: if two functions have same priority the last one added will be called first.

popCheckFunc: function

Optional function to call once route is allowed to check whether to remove the check or not. NOTE: if popOnceRouteAllowed is set to true this function is useless