Skip to content

Instantly share code, notes, and snippets.

@max107
Created November 23, 2015 17:24
Show Gist options
  • Save max107/829d114673aca7754494 to your computer and use it in GitHub Desktop.
Save max107/829d114673aca7754494 to your computer and use it in GitHub Desktop.
easy-react-router
export { default as Router } from './router';
export { default as Link } from './link';
export { default as Store } from './store';
import React, { Component, PropTypes } from 'react';
import Route from 'route-parser';
import _ from 'lodash';
import Qs from 'qs';
import urlJoin from 'url-join';
import store from './store';
export default class Router extends Component {
_unlisten = null;
static propTypes = {
history: PropTypes.object.isRequired,
routes: PropTypes.object.isRequired
};
state = {
route: {
component: null,
wrapper: null,
params: {}
}
};
static childContextTypes = {
router: PropTypes.object
};
getChildContext() {
return {
router: {
to: this.transitionTo.bind(this),
transitionTo: this.transitionTo.bind(this),
reverse: this.reverse.bind(this),
navigate: this.navigate.bind(this)
}
};
}
transitionTo(to, params = {}, query = {}) {
this.navigate(this.reverse(to, params, query));
}
navigate(url) {
this.props.history.pushState(null, url);
}
createRoutes() {
const { routes } = this.props;
for (let name in routes) {
let { path, component, wrapper } = routes[name];
store.set(name, {route: new Route(path), component, wrapper});
}
}
urlFromLocation(location) {
if (location.search.length > 0) {
return urlJoin('/', location.pathname, location.search);
} else {
return urlJoin('/', location.pathname);
}
}
parseUrl(url) {
let routes = store.all();
for (let name in routes) {
let { route, component, wrapper } = routes[name];
let params = route.match(url);
if (params) {
return {params, component, wrapper};
}
}
throw new Error('Unknown route');
}
componentWillUnmount() {
this._unlisten();
}
componentWillMount() {
this.createRoutes();
const { history } = this.props;
this._unlisten = history.listen(location => {
this.setState({
location,
route: this.parseUrl(this.urlFromLocation(location))
});
});
}
reverse(to, params = {}, query = {}) {
if (!to || to.length == 0) {
throw new Error('Route cannot be empty');
}
params = params || {};
query = query || {};
let queryString = '';
if (Object.keys(query).length) {
queryString = '?' + Qs.stringify(query);
}
let { route } = store.get(to);
return route.reverse(params) + queryString;
}
render() {
const { route, location } = this.state;
let query = Qs.parse(location.search.substring(1));
let props = {
params: route.params,
query: query
};
if (route.wrapper) {
let children = React.createElement(route.component, props);
return React.createElement(route.wrapper, props, children);
} else {
return React.createElement(route.component, props);
}
}
}
export default {
_routes: {},
get(name) {
if (this.has(name) == false) {
throw new Error('Route with name ' + name + ' not found');
}
return this._routes[name];
},
has(name) {
return name in this._routes;
},
set(name, params) {
if (this.has(name)) {
throw new Error('Route with name ' + name + ' already exists');
}
this._routes[name] = params;
},
all() {
return this._routes;
}
}
@max107
Copy link
Author

max107 commented Nov 23, 2015

Usage:

import Dashboard from 'handlers/test';
import AppTest from 'app/app_test';
let newRoutes = {
    default: {
        name: 'default',
        path: '/news/list',
        component: Dashboard,
        wrapper: AppTest
    }
};

render((
    <Provider store={store}>
        <EasyRouter history={history} routes={newRoutes} />
    </Provider>
), document.getElementById('app'));

@max107
Copy link
Author

max107 commented Nov 23, 2015

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment