Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/kitze/mobx-router

A simple router for MobX + React apps
https://github.com/kitze/mobx-router

history hooks lifecycle-events mobx react router

Last synced: about 1 month ago
JSON representation

A simple router for MobX + React apps

Awesome Lists containing this project

README

        

### πŸ™‹β€β™‚οΈ Made by [@thekitze](https://twitter.com/thekitze)

### Other projects:
- 🏫 [React Academy](https://reactacademy.io) - Interactive React and GraphQL workshops
- πŸ’Œ [Twizzy](https://twizzy.app) - A standalone app for Twitter DM
- πŸ’» [Sizzy](https://sizzy.co) - A tool for testing responsive design on multiple devices at once
- πŸ€– [JSUI](https://github.com/kitze/JSUI) - A powerful UI toolkit for managing JavaScript apps

Zero To Shipped

---

# 〽️ MobX Router

### Example usage
* [Demo project](http://mobx-router-example.netlify.com/)
* [Demo project repo](https://github.com/kitze/mobx-router-example)
* [Demo project repo with typescript](https://github.com/thdk/mobx-router-typescript-example)

## Inspiration
[πŸ“– How to decouple state and UI - a.k.a. you don’t need componentWillMount](https://medium.com/@mweststrate/how-to-decouple-state-and-ui-a-k-a-you-dont-need-componentwillmount-cc90b787aa37#.k9tvf5nga)

## Features
- Decoupled state from UI
- Central route configuration
- URL changes are triggering changes directly in the store, and vice-versa
- No need to use component lifecycle methods like `componentWillMount` to fetch data or trigger a side effect in the store
- Supported callbacks for the routes are: `beforeEnter`, `onEnter`, `beforeExit`, `onExit`. All of the callbacks receive `route`, `params`, `store`, and `queryParams` as parameters. If the `beforeExit` or `beforeEnter` methods return `false` the navigation action will be prevented.
- The current URL params and query params are accessible directly in the store `store.router.params` / `store.router.queryParams` so basically they're available everywhere without any additional wrapping or HOC.
- Navigating to another route happens by calling the `goTo` method on the router store, and the changes in the url are reflected automatically. So for example you can call `router.goTo(routes.book, {id:5, page:3})` and after the change is made in the store, the URL change will follow. You never directly manipulate the URL or the history object.
- `` component which also populates the href attribute and works with `middle click` or `cmd/ctrl + click`
- Typescript support (Converted to typescript by [thdk](https://github.com/thdk))
- Hash-based routing (using paths like `/#/foo/bar`) support

### Implementation
```js
import React, {createContext} from 'react';
import ReactDOM from 'react-dom';

import {MobxRouter, RouterStore, startRouter} from 'mobx-router';
import routes from 'config/routes';

//example mobx store
export class AppStore {
title = 'MobX Router Example App',
user = null
}

export class RootStore {
public router: RouterStore;
public app: AppStore;

constructor() {
this.router = new RouterStore(this);
this.app = new AppStore();
}
}

const store = new RootStore();

// Use React context to make your store available in your application
const StoreContext = createContext({});
const StoreProvider = StoreContext.Provider;

startRouter(routes, store);

ReactDOM.render(


, document.getElementById('root')
)
```

### Example config

/config/routes.js

```js
import React from 'react';

//models
import {Route} from 'mobx-router';

//components
import Home from 'components/Home';
import Document from 'components/Document';
import Gallery from 'components/Gallery';
import Book from 'components/Book';
import UserProfile from 'components/UserProfile';

const routes = {
home: new Route({
path: '/',
component:
}),
userProfile: new Route({
path: '/profile/:username/:tab',
component: ,
onEnter: () => {
console.log('entering user profile!');
},
beforeExit: () => {
console.log('exiting user profile!');
},
onParamsChange: (route, params, store) => {
console.log('params changed to', params);
}
}),
gallery: new Route({
path: '/gallery',
component: ,
onEnter: (route, params, store, queryParams) => {
store.gallery.fetchImages();
console.log('current query params are -> ', queryParams);
},
beforeExit: () => {
const result = confirm('Are you sure you want to leave the gallery?');
return result;
}
}),
document: new Route({
path: '/document/:id',
component: ,
beforeEnter: (route, params, store) => {
const userIsLoggedIn = store.app.user;
if (!userIsLoggedIn) {
alert('Only logged in users can enter this route!');
return false;
}
},
onEnter: (route, params) => {
console.log(`entering document with params`, params);
}
}),
book: new Route({
path: '/book/:id/page/:page',
component: ,
onEnter: (route, params, store) => {
console.log(`entering book with params`, params);
store.app.setTitle(route.title);
}
})
};
export default routes;
```

### Custom director configuration

*mobx-router* uses [director](https://github.com/flatiron/director) behind the scenes. mobx-router exposes the director config object for you to pass your own configuration to director.

To do this you must pass a `DirectorConfig` object as third argument of `startRouter` method.

**Hash based Routing | html5history**

If you disable html5history option, mobx will fallback to hash based routing.
```js
startRouter(
routes,
store,
{
// https://github.com/flatiron/director#configuration
html5history: false,
}
);
```

**Not found (404) route | notfound**

You can pass a function to `notfound` which will be called when you don't have any matching route for the current path.

```js
startRouter(
routes,
store,
{
// https://github.com/flatiron/director#configuration
notfound: () => store.router.goTo(YOUR_NOT_FOUND_ROUTE),
}
);
```