Item de link React-Bootstrap em um navitem

86

Estou tendo alguns problemas de estilo ao usar o react-router e o react-bootstrap. abaixo está um snippet do código

import { Route, RouteHandler, Link } from 'react-router';
import AuthService from '../services/AuthService'
import { Button, Nav, Navbar, NavDropdown, MenuItem, NavItem } from 'react-bootstrap';

    <Nav pullRight>
      <NavItem eventKey={1}>
        <Link to="home">Home</Link>
      </NavItem>
      <NavItem eventKey={2}>
        <Link to="book">Book Inv</Link>
      </NavItem>
      <NavDropdown eventKey={3} title="Authorization" id="basic-nav-dropdown">
        <MenuItem eventKey="3.1">
          <a href="" onClick={this.logout}>Logout</a>
        </MenuItem>          
      </NavDropdown>  
    </Nav>

Isso é o que parece quando ele é renderizado.

insira a descrição da imagem aqui

Eu sei que <Link></Link>está causando isso, mas não sei por quê? Eu gostaria que isso fosse alinhado.

chad schmidt
fonte

Respostas:

5

Você não deve colocar âncora dentro NavItem. Ao fazer isso, você verá um aviso no console:

Warning: validateDOMNesting(...): <a> cannot appear as a descendant of <a>. See Header > NavItem > SafeAnchor > a > ... > Link > a.

Isso porque, quando NavItemé renderizada, uma âncora (filho direto de NavItem) já está lá.

Por causa do aviso acima, o react será forçado a tratar os dois âncoras como irmãos, o que causou o problema de estilo.

Ming
fonte
4
Eu tive que acabar usando um contêiner de link .
chad schmidt,
3
Você poderia dar um exemplo?
Paschalidis Christos
5
Sou o único cujo problema é resolvido não por uma resposta aceita, mas pela segunda resposta.
Ejaz Karim
1
@chadschmidt altere a resposta aceita para stackoverflow.com/a/36933127/1826429
Goldy
249

Usar o LinkContainer do react -router-bootstrap é o caminho a percorrer. O código a seguir deve funcionar.

import { Route, RouteHandler, Link } from 'react-router';
import AuthService from '../services/AuthService'
import { Button, Nav, Navbar, NavDropdown, MenuItem, NavItem } from 'react-bootstrap';
import { LinkContainer } from 'react-router-bootstrap';

/// In the render() method
<Nav pullRight>
  <LinkContainer to="/home">
    <NavItem eventKey={1}>Home</NavItem>
  </LinkContainer>
  <LinkContainer to="/book">
    <NavItem eventKey={2}>Book Inv</NavItem>
  </LinkContainer>
  <NavDropdown eventKey={3} title="Authorization" id="basic-nav-dropdown">
    <LinkContainer to="/logout">
      <MenuItem eventKey={3.1}>Logout</MenuItem>    
    </LinkContainer>      
  </NavDropdown>  
</Nav>

Esta é principalmente uma nota para o eu futuro, ao pesquisar esse problema no Google. Espero que outra pessoa possa se beneficiar com a resposta.

Gennon
fonte
4
que tal alternar o activeClassName?
Anyul Rivas
Se você não conseguir fazer isso funcionar, certifique-se de que seu caminho esteja incluído no Roteador React.
Anant Simran Singh
8
Isso falha em aplicar o estilo "ativo" aos NavItems.
Daniel Arant
1
Eu adicionei uma resposta abaixo que resolve o problema com active / activeKey não funcionando. Também funciona com o react-bootstrap v_1.0 beta! (Para usar com a versão normal, basta inserir o Nav.Item do NavItem, e assim por diante)
Young Scooter
52

Atualiz 2020: testado com react-boostrap: 1.0.0-beta.16ereact-router-dom: 5.1.2

Atualização 2019: para aqueles que estão trabalhando com react -bootstrap v4 (usando 1.0.0-beta.5 atualmente) e react-router-dom v4 (4.3.1) basta usar "como" prop de Nav.Link, aqui está completo exemplo:

import { Link, NavLink } from 'react-router-dom'
import { Navbar, Nav } from 'react-bootstrap'

<Navbar>
  {/* "Link" in brand component since just redirect is needed */}
  <Navbar.Brand as={Link} to='/'>Brand link</Navbar.Brand>
  <Nav>
    {/* "NavLink" here since "active" class styling is needed */}
    <Nav.Link as={NavLink} to='/' exact>Home</Nav.Link>
    <Nav.Link as={NavLink} to='/another'>Another</Nav.Link>
    <Nav.Link as={NavLink} to='/onemore'>One More</Nav.Link>
  </Nav>
</Navbar>

Aqui está um exemplo de trabalho: https://codesandbox.io/s/3qm35w97kq

Alexey
fonte
acabei de experimentar, mas não funciona com 'as = {NavLink}'.
lannyboy
1
Isso funciona no roteador react v5 com react-bootstrap 1 e react 16.8
proc
Eu venho do Vue.js, onde o boostrap vue simplesmente implementa e gerencia o parâmetro "para" e acho isso muito mais fácil. Obrigado pela dica mesmo assim, ajudou muito!
egdavid
1
Use esta solução, em vez de LinkContainerpartir react-router-bootstrap, porque esta solução suporta activeClassName.
takasoft
Obrigado @Alexey. Passei horas tentando fazer o LinkContainer funcionar e então encontrei esta resposta.
David Easley
31

Você já tentou usar o react-bootstrap's componentClass?

import { Link } from 'react-router';
// ...
<Nav pullRight>
  <NavItem componentClass={Link} href="https://stackoverflow.com/" to="/">Home</NavItem>
  <NavItem componentClass={Link} href="https://stackoverflow.com/book" to="/book">Book Inv</NavItem>
</Nav>
sonlexqt
fonte
1
Isso funciona bem! Sem problemas de estilo e muito mais simples do que as outras respostas que exigem substituição, você também pode substituir com um HoC apenas para evitar a repetição do href / to.
Tim Lind,
1
Isso é tão limpo, usei agora com "target blank" para um link externo e funciona muito bem. Obrigado
Saulo Gomes
1
Isso é melhor, sem a necessidade de incluir outro pacote.
sbk201
2
Acabei de atualizar para 1.0.0-beta.5. Parece que eles removeram o suporte para componentClass :(
Nate-Bit Int
12

Você pode evitar o uso LinkContainerde react-router-bootstrap. No entanto, componentClassvai se tornar asno próximo lançamento. Portanto, você pode usar o seguinte snippet para a última versão (v1.0.0-beta):

<Nav>
    <Nav.Link as={Link} to="/home" >
        Home
    </Nav.Link>
    <Nav.Link as={Link} to="/book" >
        Book Inv
    </Nav.Link>
    <NavDropdown title="Authorization" id="basic-nav-dropdown">
        <NavDropdown.Item onClick={props.logout}>
            Logout
        </NavDropdown.Item>
    </NavDropdown>
</Nav>
Alexey Kutalo
fonte
5

Aqui está uma solução para uso com o roteador react 4:

import * as React from 'react';

import { MenuItem as OriginalMenuItem, NavItem as OriginalNavItem } from 'react-bootstrap';

export const MenuItem = ({ href, ...props }, { router }) => (
  <OriginalMenuItem onClick={e => {e.preventDefault();router.transitionTo(href)}} href={href} {...props}/>
);

MenuItem.contextTypes = {
  router: React.PropTypes.any
};

export const NavItem = ({ href, ...props }, { router }) => (
  <OriginalNavItem onClick={e => {e.preventDefault();router.transitionTo(href)}} href={href} {...props}/>
);

NavItem.contextTypes = {
  router: React.PropTypes.any
};
ataque vodu
fonte
Em vez de router.transitionTo(href)usarrouter.history.push(href)
Devasatyam
3

IndexLinkContainer é uma opção melhor do que LinkContainer se você quiser que o NavItem interno destaque qual está ativo com base na seleção atual. Nenhum manipulador de seleção manual é necessário

import { IndexLinkContainer } from 'react-router-bootstrap';
....

//Inside render
<Nav bsStyle="tabs" >
  <IndexLinkContainer to={`${this.props.match.url}`}>
    <NavItem >Tab 1</NavItem>
  </IndexLinkContainer>
  <IndexLinkContainer to={`${this.props.match.url}/tab-2`}>
    <NavItem >Tab 2</NavItem>
  </IndexLinkContainer>
  <IndexLinkContainer to={`${this.props.match.url}/tab-3`}>
    <NavItem >Tab 3</NavItem>
  </IndexLinkContainer>
</Nav>
Sairam Krish
fonte
Não estou usando guias, mas gostaria que o link na minha barra de navegação fosse destacado como ativo. Tentei usar o IndexLinkContainer e não funciona como você indicou. Se eu for diretamente para uma rota, ela destacará a correta, mas não se eu apenas clicar nos links.
Thomas Le
a propósito, apenas curiosidade, como você encontrou IndexLinkContainer? não consegui encontrar em nenhum lugar nos docs ...
Thiem Nguyen
@ThomasLe Verifique se você está usando Component vs PureComponent. Eu tive alguns problemas atualizados corrigidos ao mudar para o componente
FrozenKiwi
2

Você pode usar o histórico , apenas certifique-se de criar o componente com o roteador :

em App.js:

// other imports
import {withRouter} from 'react-router';

const NavigationWithRouter = withRouter(Navigation);

//in render()
    <NavigationWithRouter />

em Navigation.js:

//same code as you used before, just make an onClick event for the NavItems instead of using Link

<Nav pullRight>
  <NavItem eventKey={1} onClick={ e => this.props.history.push("/home") } >
    Home
  </NavItem>
  <NavItem eventKey={2} onClick={ e => this.props.history.push("/book") } >
    Book Inv
  </NavItem>
</Nav>
5ar
fonte
0

Para adicionar funcionalidade com prop "activeKey" no react-bootstrap v_1.0 beta, use este formato:

<Nav activeKey={//evenKey you want active}>
    <Nav.Item>
        <LinkContainer to={"/home"} >
            <Nav.Link eventKey={//put key here}>
                {x.title}
            </Nav.Link>
        </LinkContainer>
    </Nav.Item>
    //other tabs go here
</Nav>
Scooter Jovem
fonte