Closed IniZio closed 5 years ago
Interesting idea. I haven't used this library, but it may be a matter of defining a "link generator".
const generateLink = ({ to, ...rest }) => {
// Return whatever you want
return <MyCustomLink href={to} {...rest} />
})
const ArticleLocation = new Location('/articles/:id', { id: Yup.number() /* ... */ }, { generateLink });
const ArticleLink = ArticleLocation.toLink('Article 1', { id: 1 })
// => <MyCustomLink href='/articles/1' />
Of course it's a little bit verbose to specify this on every Location, so some global configuration would probably be better.
It might be nice if there was a separate Location
just for sane react-router defaults, maybe like:
import ReactRouterLocation from 'react-app-location/react-router-location'
To allow tree shaking to eliminate react-router for non-react-router apps.
Actually, when I think about it more, it could be a matter of simply hiding toLink
and toRoute
between another package (toUrl
is already agnostic). To mimic the example from the README:
import React from "react";
import { Link, BrowserRouter, Switch, Route } from 'react-router-dom';
import * as Yup from 'yup';
import Location from "react-app-location";
+ import { toRoute, toLink } from "react-app-location/react-router";
const HomeLocation = new Location('/');
const ArticleLocation = new Location('/articles/:id', { id: Yup.number().integer().positive().required() });
const App = () => (
<BrowserRouter>
<Switch>
{/* Regular Route */}
<Route path={HomeLocation.path} component={Home} exact />
{/* Route with params automatically passed as props to your component */}
- {ArticleLocation.toRoute({ component: Article, invalid: NotFound }, true)}
+ {toRoute(ArticleLocation, { component: Article, invalid: NotFound }, true)}
<Route component={NotFound} />
</Switch>
</BrowserRouter>
);
const Home = () => (
<div>
<header>Articles</header>
<ul>
{/* <Link to={'/articles/1'}>Article 1</Link> */}
- <li>{ArticleLocation.toLink('Article 1', {id: 1})}</li>
+ <li>{toLink(ArticleLocation, 'Article 1', {id: 1})}</li>
{/* <Link to={'/articles/2'}>Article 2</Link> */}
- <li>{ArticleLocation.toLink('Article 2', {id: 2})}</li>
+ <li>{toLink(ArticleLocation, 'Article 2', {id: 2})}</li>
{/* Also works */}
<li><Link to={ArticleLocation.toUrl({id: 3})}>Article 3</Link></li>
{/* Clicking results in <NotFound /> */}
<li><Link to={ArticleLocation.toUrl({id: 'oops-not-an-int'})}>Article 4</Link></li>
{/* Also results in <NotFound /> */}
<li><Link to={'/articles/oops-not-an-int'}>Article 5</Link></li>
</ul>
</div>
);
//id has been parsed from the URL, cast to int, and merged into props
const Article = ({id}) => <header>`Article ${id}`</header>;
const NotFound = () => (
<div>
<header>Page not found</header>
<p>Looks like you have followed a broken link or entered a URL that does not exist on this site.</p>
</div>
);
I'm for it.
toUrl
and parseLocationParams
would be moved to a base (router-agnostic) package, and toRoute
and toLink
would be remain in the package that depends on react-router.
But I also want to provide a way to provide automatic location param injection in the base package (currently only available via toRoute
). My current thought is to build a withLocationParams
HOC that would take an App Location definition, parse the parameters from the URL, and pass them as props.
What do you guys think of that?
Would be nice, maybe could use a pub/sub mechanism though so that it is easier to do same thing in other frameworks like Vue.js?
I built app-location, which is router-agnostic and framework-agnostic. And I changed react-app-location
to extend app-location
by providing integration with React Router 4.
Since the package has been released, guess this issue can be closed? Thanks for the code :wink:
Currently toLink / toRoute will always convert to react-router components, but some frameworks like Nextjs use their own routing components.
This library is underrated and I feel like it can in fact be made language-agnostic?