Keep your MobX state in sync with react-router via a RouterStore
npx @tessl/cli install tessl/npm-ibm--mobx-react-router@6.1.0MobX React Router provides seamless integration between MobX observable state management and React Router by offering a RouterStore class that makes router location state observable, enabling MobX components to automatically re-render when navigation occurs. The library includes a syncHistoryWithStore function that synchronizes browser history with the MobX store, providing navigation methods and subscription capabilities for location changes.
npm install @ibm/mobx-react-routerimport { RouterStore, syncHistoryWithStore } from "@ibm/mobx-react-router";For CommonJS:
const { RouterStore, syncHistoryWithStore } = require("@ibm/mobx-react-router");import React from 'react';
import ReactDOM from 'react-dom';
import { createBrowserHistory } from 'history';
import { Provider } from 'mobx-react';
import { RouterStore, syncHistoryWithStore } from '@ibm/mobx-react-router';
import { Router } from 'react-router';
import App from './App';
// Create history and router store
const browserHistory = createBrowserHistory();
const routingStore = new RouterStore();
// Sync history with store
const history = syncHistoryWithStore(browserHistory, routingStore);
// Use in your app
const stores = {
routing: routingStore,
// ...other stores
};
ReactDOM.render(
<Provider {...stores}>
<Router location={routingStore.location} navigator={history}>
<App />
</Router>
</Provider>,
document.getElementById('root')
);MobX React Router bridges the gap between MobX observable state management and React Router navigation through a simple yet powerful architecture:
location and history) and provides navigation methodsObservable MobX store that wraps router state and provides navigation methods.
/**
* Observable MobX store for router state management
*/
class RouterStore {
/** Observable location object (initially null) */
location: Location | null;
/** History API object (set by syncHistoryWithStore) */
history: History | null;
/** Creates a new RouterStore instance with observable location and history properties */
constructor();
/** Navigate to new location using history.push */
push(location: string | Partial<Location>, state?: any): void;
/** Replace current location using history.replace */
replace(location: string | Partial<Location>, state?: any): void;
/** Navigate n steps in history using history.go */
go(n: number): void;
/** Navigate back one step using history.back */
back(): void;
/** Navigate forward one step using history.forward */
forward(): void;
/** Internal method for updating location state (called by syncHistoryWithStore) */
_updateLocation(newState: Location): void;
}Usage Example:
import { inject, observer } from 'mobx-react';
@inject('routing')
@observer
export default class App extends Component {
render() {
const { location, push, back } = this.props.routing;
return (
<div>
<span>Current pathname: {location.pathname}</span>
<button onClick={() => push('/test')}>Change url</button>
<button onClick={() => back()}>Go Back</button>
</div>
);
}
}Synchronizes a history object with a RouterStore instance, creating bidirectional binding between browser history and MobX observable state.
/**
* Synchronizes browser history with RouterStore
* @param history - A history object (from history package)
* @param store - A RouterStore instance
* @returns Enhanced history object with subscription methods
*/
function syncHistoryWithStore(
history: History,
store: RouterStore
): SynchronizedHistory;
interface SynchronizedHistory extends History {
/** Subscribe to location changes in the store */
subscribe(listener: (location: Location, action: string) => void): UnregisterCallback;
/** Unsubscribe from history updates (store will no longer update) */
unsubscribe(): void;
}Usage Examples:
import { createBrowserHistory } from 'history';
import { RouterStore, syncHistoryWithStore } from '@ibm/mobx-react-router';
const browserHistory = createBrowserHistory();
const routingStore = new RouterStore();
const history = syncHistoryWithStore(browserHistory, routingStore);
// Subscribe to location changes
const unsubscribe = history.subscribe((location, action) => {
console.log(`Navigated to ${location.pathname} via ${action}`);
});
// Navigate programmatically
history.push('/dashboard');
history.replace('/settings');
// Clean up subscription
unsubscribe();
// Completely unsubscribe from history updates
history.unsubscribe();/** Callback function for unregistering listeners */
type UnregisterCallback = () => void;
/** Location object from history package */
interface Location {
pathname: string;
search: string;
hash: string;
state?: any;
key?: string;
}
/** History object from history package */
interface History {
length: number;
action: string;
location: Location;
push(path: string | Partial<Location>, state?: any): void;
replace(path: string | Partial<Location>, state?: any): void;
go(n: number): void;
back(): void;
forward(): void;
listen(listener: (location: Location, action: string) => void): UnregisterCallback;
}
/** History listener function type */
type Listener = (location: Location, action: string) => void;This library delegates navigation to the underlying history object and does not throw its own errors. Error handling should follow the patterns established by the history package being used.
MobX Considerations:
makeAutoObservable with autoBind: true_updateLocation method is called internally and should not be called directly by application codepush, replace, go, back, forward) delegate to the underlying history object