Skip to content

v4 beta: How to use Link with NavItem(react-bootstrap) #4463

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
thnt opened this issue Feb 4, 2017 · 13 comments
Closed

v4 beta: How to use Link with NavItem(react-bootstrap) #4463

thnt opened this issue Feb 4, 2017 · 13 comments

Comments

@thnt
Copy link

thnt commented Feb 4, 2017

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>
@vasa-chi
Copy link

vasa-chi commented Feb 4, 2017

Yep, seems that <Link> doesn't do function-as-children anymore. Current "custom link" example only shows how to wrap the router link.

@timdorr
Copy link
Member

timdorr commented Feb 5, 2017

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.

@timdorr timdorr closed this as completed Feb 5, 2017
@vasa-chi
Copy link

vasa-chi commented Feb 5, 2017

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...

@thomasdola
Copy link

thomasdola commented Feb 5, 2017

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..

@jgoux
Copy link

jgoux commented Feb 7, 2017

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>

@kachkaev
Copy link

kachkaev commented Feb 25, 2017

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?

@vasa-chi
Copy link

vasa-chi commented Feb 25, 2017

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 #4463 (comment), but you will lose all the subtleties of Link's onClick.

@kachkaev
Copy link

kachkaev commented Mar 4, 2017

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?

@kachkaev
Copy link

kachkaev commented Mar 4, 2017

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.

@khankuan
Copy link

@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>

@preethijayanthi
Copy link

anybody can give a code for href in navitem without using router

@eyerean
Copy link

eyerean commented Nov 8, 2017

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="https://github.com/economies" to="/economies" active={location.pathname === '/economies'}>Economies</NavItem>
            <NavItem componentClass={Link} href="https://github.com/industries" to="/industries" active={location.pathname === '/industries'}>Industries</NavItem>
        </Nav>
    <NavBar>
// ...

Works with
"react-router-dom": "^4.2.2"
"react-bootstrap": "^0.31.5"

@remix-run remix-run deleted a comment from azizur May 5, 2018
@x-yuri

This comment has been minimized.

@remix-run remix-run locked and limited conversation to collaborators Jun 5, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants