Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save nonsensecreativity/0dde4565f09befa0360d99e093a7d78d to your computer and use it in GitHub Desktop.
Save nonsensecreativity/0dde4565f09befa0360d99e093a7d78d to your computer and use it in GitHub Desktop.
/**
* I'd like to have a router with semantics that work like this
* Pros:
* - Named routes
* - Type Safe routing (with TypeScript)
* - Links are not strings so refactoring/changing them is trivial
* - Relative links are possible
*
* Cons:
* - Verbose links
* - Relative links are weak, inconvenient, and long
*
*/
import { Router, Route, Link } from 'router';
import { url } from 'route/matcher';
const AppRouter = Router({ browserHistory }, {
Index: Route('/', App, {
About: Route('about', About),
Users: Route('users', Users, {
User: Route<number>(url`/user/${ {userId: Number} }`, User, {
Page: Route<string>(url`/${ {page: String} }`, UserPage)
})
},
NoMatch: Route('*', NoMatch))
}
});
render(<AppRouter/>, document.getElementById('root'));
// Where Links look like this:
<Link to={AppRouter.Index.Users.User.link(userId)} />;
<Link to={AppRouter.Users.User.Page.link(userId, page)} />;
// Relative links
route = this.context.route || this.props.route;
// From /users/id/page1 to /users/id/page2
<Link to={route.link(page2) />;
// From /users/id to /users/id/page
<Link to={route.Page.link(page)} />;
// From /users/id/page to /users/id2
<Link to={route.parent.User.link(id2)} />;
// From /users/id/page to /users/id2/page2
<Link to={route.parent.User.Page.link(id2, page2)} />;
/**
* Pros:
* - Named routes
* - Type Safe routing (with TypeScript)
* - Links are not strings so refactoring/changing them is trivial
*
* Cons:
* - No declarative route hierarchy
* - Verbose
* - Relative linking difficult/impossible
*/
import { Router, Route, Link } from 'router';
import RouteFactory from 'route-factory';
const IndexRoute = RouteFactory('/', App);
const AboutRoute = IndexRoute.addRoute('about', About);
const UsersRoute = IndexRoute.addRoute('users', Users);
const UserRoute = UsersRoute.addRoute<number>('/user/:userId', User);
const NoMatchRoute = IndexRoute.addRoute('*', NoMatch);
render((
<Router history={browserHistory}>
<IndexRoute/>
</Router>
), document.getElementById('root'));
// Where Links look like this:
<Link to={UserRoute.link(userId)} />;
/**
* Pros:
* - Short natural links
* - Relative linking is possible
*
* Cons:
* - No Named routes
* - No Type Safe routing, everything is a string
* - Links are strings so refactoring/changing them is tedious
*/
import { Router, Route, Link } from 'react-router';
render((
<Router history={browserHistory}>
<Route path="/" component={App}>
<Route path="about" component={About}/>
<Route path="users" component={Users}>
<Route path="/user/:userId" component={User}/>
</Route>
<Route path="*" component={NoMatch}/>
</Route>
</Router>
), document.getElementById('root'));
// Where Links look like this:
<Link to=`/users/user/${userId}` />;
// Relative links? (cannot be done yet)
// From /users/id/page1 to /users/id/page2
<Link to=`../${page2}` />;
// From /users/id to /users/id/page
<Link to=`./${page}` />;
// From /users/id/page to /users/id2
<Link to=`../../${id2}` />;
// From /users/id/page to /users/id2/page2
<Link to=`../../${id2}/${page2}` />;
export default function RouteFactory = ({ path, component }) => {
const childRoutes = [];
const route = props => (
<Route path={path} component={component}>
${childRoutes}
</Route>
);
route.addRoute = (p, component) => {
const childRoute = RouteFactory(path+p, component);
childRoutes.push(childRoute);
return childRoute;
}
pathArgRegex = /:[^\/A-Za-z]+/g;
route.link = (...args) => {
let index = 0;
const result = path.replace(pathArgRegex, function() {
return args[index++];
});
if (index !== args.length) throw Error("link doesn't have enough args");
return result;
}
return route;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment