I've run into a situation where I have a component like this:
<TabLink href="#" onClick={() => {}}>Oh hi, I'm a tab</TabLink>
It's pretty much just a wrapper for an <a> tag that provides some styling to make it look like a tab. I want to use this tab as a router link, but I can't do that easily using the existing NavLink or Link components because I don't want to introduce a dependency on RR to the module the component lives in and I also don't want to have to export a RR-specific version of the component from that module. I think a great option would be to provide a HOC that enables using RR with components that take an <a>-like set of props, without them needing to have specific knowledge of RR or use NavLink explicitly.
Here's a contrived example of it'd be used with the component I described above:
import { routerLink } from 'react-router-dom';
const TabLink = ({ href, onClick }) => (
<a href={href} onClick={onClick} className="tab">
{children}
</a>
);
const RouterTabLink = routerLink(TabLink);
const MyTabs = () => (
<div class="tab-set">
<RouterTabLink to="/somewhere">Go somewhere</RouterTabLink>
<RouterTabLink to="/somewhere-else">Go somewhere else</RouterTabLink>
</div>
);
I've seen some of the criticisms around supporting a component or render prop and I agree that it's an awkward pattern and can lead to all kinds of problems since you're allowing users to inject whatever they like into one of your components. My feeling is that because the HOC approach inverts the relationship so that the consumer is explicitly expected to do something with some props they're given, it'd be much more transparent and less likely to cause confusion. It also allows composition with a whole bunch of existing components, which would be very handy!
Hopefully I've made the case for this! I'm happy to submit a PR if it sounds like something you'd want to include.
because I don't want to introduce a dependency on RR to the module the component lives in and I also don't want to have to export a RR-specific version of the component from that module.
I'm a bit confused on this specific part. What's the reasoning for not doing this? You have to import libraries into modules all the time. I don't see why wrapping Link would be a bad thing.
@timdorr the component I'm using is from a common UI library, so it's used in a bunch of different applications and most of them aren't using RR. To me RR is an implementation detail of each application and I don't really want to introduce it at the UI library's level as a dependency, but also more importantly I don't want to provide RR-specific versions of these generic components. I could do it, but I'd prefer it if that was left up to the consumer.
That said I think it's a handy tool for re-use even within the same application. There's no need to code up two versions of the same button if you can just code one for regular links and then wrap it to create RR links. Just write to a generic interface (provide href and onClick props), wrap it up and you're done!
Hope that explains where I'm coming from a bit better.
You can wrap it in withRouter, which gives it this.props.history.push as a means to push a new URL when clicking. You could easily wrap that up in a small HoC to check if history was a provided prop and then generate an onClick handler appropriately.
Unfortunately, I don't see this as a common use case. Most people are all-in on a router, since it's fairly core to any application. I appreciate the idea, but it's not something we're going to implement here.
I think this isn't that uncommon of a use case.
I also have a case where I want to style link components and I have had to create a styled-component which wraps the Link component which now has created a dependency on react-router in my component library.
Now that we are looking to move our component library somewhere where other repositories can use it - this is an issue as we are not using the same version of react-router in all our applications.
Going to echo others and say it's not uncommon. I'm facing it now with material-ui. Even react-router-native has a component prop that does what is needed here.
I'm also encountering this use case. I would prefer a single common component, but the developer using the component can choose between HTML anchors and or React Router Links.
@gpoole Is this example what you mean by a render props solution?
Most helpful comment
I think this isn't that uncommon of a use case.
I also have a case where I want to style link components and I have had to create a styled-component which wraps the
Linkcomponent which now has created a dependency on react-router in my component library.Now that we are looking to move our component library somewhere where other repositories can use it - this is an issue as we are not using the same version of react-router in all our applications.