Created
November 23, 2015 17:24
-
-
Save max107/829d114673aca7754494 to your computer and use it in GitHub Desktop.
easy-react-router
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export { default as Router } from './router'; | |
export { default as Link } from './link'; | |
export { default as Store } from './store'; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component, PropTypes } from 'react'; | |
export default class Link extends Component { | |
static propTypes = { | |
to: PropTypes.string.isRequired, | |
params: PropTypes.object, | |
query: PropTypes.object | |
}; | |
static contextTypes = { | |
router: PropTypes.object | |
}; | |
handleClick(url, e) { | |
e.preventDefault(); | |
this.getRouter().navigate(url); | |
} | |
getRouter() { | |
let router = this.context.router || this.props.router; | |
if (!router) { | |
throw new Error('Missing router in context || props'); | |
} | |
return router; | |
} | |
render() { | |
const { to, params, query } = this.props; | |
let url = this.getRouter().reverse(to, params, query); | |
return <a | |
onClick={this.handleClick.bind(this, url)} | |
href={url} | |
{...this.props}>{this.props.children}</a>; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Url parses via: https://github.com/rcs/route-parser