THIS IS EXPERIMENTAL SO IF YOU USE IT AND FIND PROBLEMS THEY ARE YOUR PROBLEMS THAT YOU MUST SOLVE, MAYBE EVEN ALL BY YOURSELF.
react-router-addons-controlled
attempts to treat <Router>
like a controlled component (think <input value onChange/>
). Unfortunately, it's not that simple. You can't actually control the browser history, so it's more a two-way data binding situation. However, in the majority of cases, it will feel like a controlled component.
Using npm:
$ npm install --save react-router-addons-controlled
Then with a module bundler like webpack, use as you would anything else:
// using an ES6 transpiler, like babel
import BrowserRouter from 'react-router-addons-controlled/ControlledBrowserRouter'
// not using an ES6 transpiler
var BrowserRouter = require('react-router-addons-controlled/ControlledBrowserRouter')
The UMD build is also available on unpkg:
<script src="https://unpkg.com/react-history/umd/react-router-addons-controlled.min.js"></script>
You can find the library on window.ReactRouterControlled
.
react-router-addons-controlled
ships with 2 different Router components that you can use depending on your environment.
<ControlledBrowserRouter>
is for use in modern web browsers that support the HTML5 history API (see cross-browser compatibility)<ControlledMemoryHistory>
is used as a reference implementation and may also be used in non-DOM environments, like React Native
There is no <ControlledHashRouter>
because hash histories can't provide all of the information we need (I don't think anyway, haven't tried.)
import Router from 'react-router-addons-controlled/ControlledBrowserRouter'
import Router from 'react-router-addons-controlled/ControlledMemoryRouter'
<Router
history={history} // the history object to listen to
location={location} // the location to navigate to
action={action} // the action to use: "PUSH" || "REPLACE",
onChange={(location, action) => { // called when the user clicks
// back/forward buttons
// if you get a "SYNC" action
// YOU MUST ACCEPT IT INTO YOUR STATE
// otherwise it's all busted
}}
{...additionalRouterProps} // all other props supported by the
// uncontrolled "sister" router
/>
So, just like with a controlled input, you respond to onChange
by setting state, or dispatching in redux.
The primary motivation for this is to make routing feel like anything else in an app that lifts state into something like redux or mobx. Let's consider Redux:
In Redux application state is kept in the "store". Changes to application state are modeled as "actions". By sticking to these two constraints, the community as able to build things on top like the Redux Devtools. So, to model routing in Redux and othe paradigms like it we need a ways to:
- Keep the router state (location and action) in the redux store (or mobx observable)
- Model changes to the location as "dispatched actions" (or mobx... uh, i-dunno-what...)
So intead of rendering a <Redirect>
or calling this.context.router.push(location)
, you can dispatch an action and pass that router state from your store to the Router and it will respond accordingly.
Please see the examples for more detailed usage: