With v4 alpha i can do this, and Link
component will not generate the <a>
tag:
<Link to="/apps">{
({ isActive, onClick, href }) =>
<NavItem active={isActive} onClick={onClick} href={href}>Apps</NavItem>
}</Link>
Yep, seems that <Link>
doesn't do function-as-children anymore. Current "custom link" example only shows how to wrap the router link.
You can do this with a render function on your Route. Just pass down the things you need from the parent. You can also use withRouter to get things off context easily.
I'm not sure that Route with a render function does the same thing. The example from documentation:
const OldSchoolMenuLink = ({ label, to, activeOnlyWhenExact }) => (
<Route path={to} exact={activeOnlyWhenExact} children={({ match }) => (
<div className={match ? 'active' : ''}>
{match ? '> ' : ''}<Link to={to}>{label}</Link>
</div>
)}/>
)
The Link
is still rendered, it's just wrapped with other components.
But you can just copy Link.js and add to it the ability to call children as function. The change is about 4 lines total...
const Animations = ({match, location}) => (
<Container>
<Header as='h2'>Animations</Header>
<Grid columns={2}>
<Grid.Row>
<Grid.Column width={3}>
<Menu size='mini' vertical fluid>
<Menu.Item name='slides' as={Link} to={`${match.url}/slides`} active={location.pathname === '/animations/slides'}>
Slides
</Menu.Item>
<Menu.Item name='drawer' as={Link} to={`${match.url}/drawer`} active={location.pathname === '/animations/drawer'}>
Drawer
</Menu.Item>
<Menu.Item name='pusher' as={Link} to={`${match.url}/pusher`} active={location.pathname === '/animations/pusher'}>
Pusher
</Menu.Item>
</Menu>
</Grid.Column>
<Grid.Column width={13}>
<Route path={`${match.url}/slides`} component={Slides}/>
</Grid.Column>
</Grid.Row>
</Grid>
</Container>
);
export default Animations;
In my case i just passed the location object which has a pathname key.
am using react.semantic-ui in this example though but the basic idea is there.
or you can the read doc
hope this helps..
FYI this is how I did with material-ui :
const Link = ({ to, children }) => (
<Route
children={history => React.cloneElement(children, {
href: to,
onClick: e => {
e.preventDefault();
history.push(to);
}
})}
/>
);
Then I use it like this :
<Link to="/users">
<MenuItem primaryText="Users" leftIcon={<ModeEditIcon />} />
</Link>
Hi guys,
Could you please explain how to handle cases when there is a custom element, only a part of which needs to play a role of clickable link? E.g. we have <ButtonWithCustomShadow onBodyClick={myHandler} title="hello" />
and onBodyClick
works for the surface of this component, but does not involve the shadow.
In v3 the solution was easy, the first comment lists it. In v4 there seems to be way to use <Link />
and not cover the entire child component because there is no place to get onClick
(or any other custom link trigger from. Or am I missing something?
Well, you probably can just inherit the Link
component and override render... I mean, it _is_ just a class.
Otherwise, you can use Route
, as in https://github.com/ReactTraining/react-router/issues/4463#issuecomment-278019089, but you will lose all the subtleties of Link
's onClick
.
Inheriting a link may seem reasonable in certain cases, like when you want a menu item that works like a link. There can be many of these in the interface, so making a custom component is worth the effort.
However, there can be situations when a link of a certain style is to appear only once in the whole app. For example, my 404 page contains something like this:
import React from 'react';
import { Button } from 'antd'; // https://ant.design/components/button/
import { Link } from 'react-router-dom'; //v3
import styled from 'styled-components';
const LayoutForErrorPage = styled.div`
text-align: center;
`;
const EmptyPageMessage = styled.div`
font-size: 2em;
margin-top: 100px;
`;
export default () => (
<LayoutForErrorPage>
<EmptyPageMessage>Page not found</EmptyPageMessage>
<Link to="/">{
({ onClick }) =>
<Button onClick={onClick} type="primary">back to home page</Button>
}</Link>
</LayoutForErrorPage>
);
The composition of link and an existing third-party button was quite straightforward in v3: no custom event handler and no new components inheriting other components. I'm not sure how to solve the same problem in v4 without introducing extra complexity. Could you please share some advice?
Inheritance example:
import React from 'react';
import { Button } from 'antd'; // https://ant.design/components/button/
import { Link } from 'react-router-dom'; // v4
import styled from 'styled-components';
const LayoutForErrorPage = styled.div`
text-align: center;
`;
const EmptyPageMessage = styled.div`
font-size: 2em;
margin-top: 100px;
`;
class LinkButton extends Link {
render() {
const {
to,
children,
...rest
} = this.props;
return (<Button {...rest} onClick={this.handleClick}>{children}</Button>);
}
}
export default () => (
<LayoutForErrorPage>
<EmptyPageMessage>Page not found</EmptyPageMessage>
<LinkButton to="/" type="primary">back to home page</LinkButton>
</LayoutForErrorPage>
);
Looks like too much for such a simple use case. Feels like some generalised wrapper is needed out of box. Being able to handle target and other props that <Link>
does is quite useful; just using <Route/>
with history.push
onClick
is probably not enough.
@vasa-chi nice tip! I've tried a Link patch that supports custom component:
export class Link extends ReactRouterLink {
static propTypes = {
...ReactRouterLink.propTypes,
component: PropTypes.any,
}
render() {
const output = super.render();
const Component = this.props.component;
if (Component) {
const props = {...output.props};
delete props.component;
return <Component {...props} />;
}
return output
}
}
// usage
<Link component={MySpecialButton} color="my-special-color" to="/">My Button</Link>
anybody can give a code for href in navitem without using router
Another solution, extending this answer from #83:
import { Link } from 'react-router-dom';
import { NavBar, Nav, NavItem} from 'react-bootstrap';
const NavBar = ({location}) => (
<NavBar>
<Nav>
<NavItem componentClass={Link} href="/economies" to="/economies" active={location.pathname === '/economies'}>Economies</NavItem>
<NavItem componentClass={Link} href="/industries" to="/industries" active={location.pathname === '/industries'}>Industries</NavItem>
</Nav>
<NavBar>
// ...
Works with
"react-router-dom": "^4.2.2"
"react-bootstrap": "^0.31.5"
It's not really clear what OP's trying to achieve (the big picture). So, the next post solution might work:
import { LinkContainer } from 'react-router-bootstrap';
<Navbar>
<Nav>
<LinkContainer exact to="/">
<NavItem>Home</NavItem>
</LinkContainer>
<LinkContainer exact to="/other-page">
<NavItem>Other Page</NavItem>
</LinkContainer>
</Nav>
</Navbar>
At least, it did for me.
Most helpful comment
Another solution, extending this answer from #83:
Works with
"react-router-dom": "^4.2.2"
"react-bootstrap": "^0.31.5"