Elemento de vínculo React-Bootstrap en un elemento de navegación

85

Tengo algunos problemas de estilo al usar react-router y react-bootstrap. a continuación se muestra un fragmento del 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>

Así es como se ve cuando se renderiza.

ingrese la descripción de la imagen aquí

Sé que <Link></Link>está causando esto, pero no sé por qué. Me gustaría que esto estuviera en línea.

chad schmidt
fuente

Respuestas:

5

No debes poner ancla en el interior NavItem. Al hacer esto, verá una advertencia en la consola:

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

Eso es porque cuando NavItemse representa un ancla (hijo directo de NavItem) ya está allí.

Debido a la advertencia anterior, react se verá obligado a tratar a los dos ancla como hermanos, lo que causó el problema de estilo.

Ming
fuente
4
Tuve que terminar usando un contenedor de enlaces .
chad schmidt
3
¿Podría dar un ejemplo?
Paschalidis Christos
5
¿Soy el único cuyo problema no se resuelve con una respuesta aceptada sino con la segunda respuesta?
Ejaz Karim
1
@chadschmidt, cambie la respuesta aceptada a stackoverflow.com/a/36933127/1826429
Goldy
247

Usar LinkContainer de react-router-bootstrap es el camino a seguir. El siguiente código debería 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>

Esto es principalmente una nota para el yo futuro, al buscar en Google este problema. Espero que alguien más pueda beneficiarse de la respuesta.

Gennon
fuente
4
¿Qué hay de alternar el activeClassName?
Anyul Rivas
Si no puede hacer que esto funcione, solo asegúrese de que su ruta esté incluida en React Router.
Anant Simran Singh
8
Esto no aplica el estilo "activo" a NavItems.
Daniel Arant
1
Agregué una respuesta a continuación que resuelve el problema con active / activeKey que no funciona. ¡También funciona con react-bootstrap v_1.0 beta! (Para usar con la versión normal, simplemente elimine Nav.Item para NavItem, y así sucesivamente)
Young Scooter
49

2020 upd: probado con react-boostrap: 1.0.0-beta.16yreact-router-dom: 5.1.2

2019 upd: para aquellos que están trabajando con react-bootstrap v4 (usando 1.0.0-beta.5 actualmente) y react-router-dom v4 (4.3.1) simplemente use "as" prop de Nav.Link, aquí está completo ejemplo:

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>

Aquí está el ejemplo de trabajo: https://codesandbox.io/s/3qm35w97kq

Alexey
fuente
acaba de probar, simplemente no funciona con 'as = {NavLink}'.
lannyboy
1
Esto funciona en react router v5 con react-bootstrap 1 y react 16.8
proc
Vengo de Vue.js donde boostrap vue simplemente implementa y administra el parámetro "to" y lo encuentro mucho más fácil. Gracias por el consejo de todos modos, ¡ayudó mucho!
egdavid
1
Utilice esta solución en lugar de LinkContainerdesde react-router-bootstrapporque esta solución admite activeClassName.
takasoft
Gracias @Alexey. Pasé horas tratando de que LinkContainer funcionara y luego encontré esta respuesta.
David Easley
31

¿Ha intentado usar 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
fuente
1
¡Esto funciona bien! Sin problemas de estilo y mucho más simple que las otras respuestas que requieren anulación, también puede anular con un HoC solo para evitar la repetición de href / to.
Tim Lind
1
Esto es tan limpio, lo usé ahora mismo con "target blank" para un enlace externo y funciona muy bien. Gracias
Saulo Gomes
1
Esto es mejor, sin necesidad de incluir otro paquete.
sbk201
2
Recién actualizado a 1.0.0-beta.5. Parece que eliminaron el soporte para componentClass :(
Nate-Bit Int
12

Puede evitar el uso LinkContainerde react-router-bootstrap. Sin embargo, componentClassse convertirá asen la próxima versión. Por lo tanto, puede usar el siguiente fragmento de código para la última versión (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
fuente
5

Aquí hay una solución para usar con react-router 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
};
vudú
fuente
En lugar de usar router.transitionTo(href)userouter.history.push(href)
Devasatyam
2

Puede usar el historial , solo asegúrese de crear el componente con el enrutador :

en App.js:

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

const NavigationWithRouter = withRouter(Navigation);

//in render()
    <NavigationWithRouter />

en 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
fuente
2

IndexLinkContainer es una mejor opción que LinkContainer si desea que el NavItem interno resalte cuál está activo en función de la selección actual. No se necesita un controlador de selección manual

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
fuente
No estoy usando pestañas, pero me gustaría que el enlace en mi barra de navegación se resalte como activo. Intenté usar IndexLinkContainer y no funciona como indicó. Si voy directamente a una ruta, resaltará la correcta, pero no si solo hago clic en los enlaces.
Thomas Le
por cierto, solo curiosidades, ¿cómo lo encontraste IndexLinkContainer? Aunque no pude encontrarlo en ninguna parte de los documentos ...
Thiem Nguyen
@ThomasLe Verifique su uso de Component vs PureComponent. He solucionado algunos problemas actualizados al cambiar a Componente
FrozenKiwi
0

Para agregar funcionalidad con "activeKey" prop en 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 joven
fuente