Zawijanie łącza React-router w przycisk html

Odpowiedzi:

170

Chociaż spowoduje to wyświetlenie w przeglądarce internetowej, pamiętaj, że:
⚠️ Zagnieżdżaniebuttona kodu HTML w html (lub odwrotnie) nie jest poprawnym kodem HTML ⚠️. Jeśli chcesz zachować semantyczny kod HTML dla czytników ekranu, użyj innego podejścia.

Zrób zawijanie w odwrotny sposób, a otrzymasz oryginalny guzik z dołączonym łączem. Nie są wymagane żadne zmiany CSS.

 <Link to="/dashboard">
     <button type="button">
          Click Me!
     </button>
 </Link>

Tutaj przycisk to przycisk HTML. Ma również zastosowanie do komponentów importowanych z bibliotek innych firm, takich jak Semantic-UI-React .

 import { Button } from 'semantic-ui-react'
 ... 
 <Link to="/dashboard">
     <Button style={myStyle}>
        <p>Click Me!</p>
     </Button>
 </Link>
Naren Yellavula
źródło
1
Dzięki, proste i działające, podczas gdy rozwiązanie css @ChaseJames nie działa. Może czegoś brakuje. Ale używam bootstrap; import { Button } from 'react-bootstrap';.
Stefano Scarpanti
3
Podczas przeglądania dokumentu przechodzisz tabulatorem do kotwicy, a następnie osobno do przycisku. Aby tego uniknąć, dodaj tabindex = "- 1" do elementu Link. Link będzie nadal śledzony (przynajmniej w przeglądarce Firefox ...), gdy przycisk zostanie aktywowany przez naciśnięcie klawisza Enter.
tremby
4
Jak wiesz, Link tworzy tag <a href="">kotwicy, a tag kotwicy nie może zawierać tagu przycisku.
taher
4
Chociaż wydaje się to działać, jest semantycznie błędne (i nieprawidłowe w HTML 5). Zobacz Czy mogę zagnieździć element <button> wewnątrz <a> przy użyciu HTML5?
imgx64
Jeśli na przykład wyłączysz przycisk, kliknięcie przycisku będzie nadal działać. Naprawdę nie ma powodu, aby używać tego hackerskiego rozwiązania w porównaniu z history.pushopcją
Burak
114

LinkButton komponent - rozwiązanie dla React Router v4

Najpierw uwaga na temat wielu innych odpowiedzi na to pytanie.

⚠️ Zagnieżdżanie <button>i <a>nieprawidłowy kod HTML. ⚠️

Każda odpowiedź tutaj, która sugeruje zagnieżdżenie html buttonw Linkkomponencie React Router (lub odwrotnie), zostanie wyświetlona w przeglądarce internetowej, ale nie jest semantyczna, dostępna ani poprawna w html:

<a stuff-here><button>label text</button></a>
<button><a stuff-here>label text</a></button>

Kliknij, aby sprawdzić poprawność tego znacznika za pomocą validator.w3.org

Może to prowadzić do problemów z układem / stylem, ponieważ przyciski zwykle nie są umieszczane w linkach.


Używanie <button>tagu html z <Link>komponentem React Router .

Jeśli chcesz tylko buttontag HTML …

<button>label text</button>

… W takim razie oto właściwy sposób na uzyskanie przycisku działającego jak Linkkomponent React Router …

Użyj React Router's withRouter HOC, aby przekazać te właściwości do swojego komponentu:

  • history
  • location
  • match
  • staticContext

LinkButton składnik

Oto LinkButtonkomponent do skopiowania / makaronu :

// file: /components/LinkButton.jsx
import React from 'react'
import PropTypes from 'prop-types'
import { withRouter } from 'react-router'

const LinkButton = (props) => {
  const {
    history,
    location,
    match,
    staticContext,
    to,
    onClick,
    // ⬆ filtering out props that `button` doesn’t know what to do with.
    ...rest
  } = props
  return (
    <button
      {...rest} // `children` is just another prop!
      onClick={(event) => {
        onClick && onClick(event)
        history.push(to)
      }}
    />
  )
}

LinkButton.propTypes = {
  to: PropTypes.string.isRequired,
  children: PropTypes.node.isRequired
}

export default withRouter(LinkButton)

Następnie zaimportuj komponent:

import LinkButton from '/components/LinkButton'

Użyj komponentu:

<LinkButton to='/path/to/page'>Push My Buttons!</LinkButton>

Jeśli potrzebujesz metody onClick:

<LinkButton
  to='/path/to/page'
  onClick={(event) => {
    console.log('custom event here!', event)
  }}
>Push My Buttons!</LinkButton>

Aktualizacja: Jeśli szukasz innej fajnej opcji dostępnej po napisaniu powyższego, sprawdź ten hook useRouter .

Beau Smith
źródło
15
To powinna być akceptowana odpowiedź. Wszystkie inne odpowiedzi to IMHO, hacki i mogą przynieść nieoczekiwane wyniki. Dziękuję Ci!
Kyle
Czy użycie komponentu trafiłoby do wnętrza <div> .. </divelementu App.js?
DJ2
@ DJ2 - Tak, lub w jakimkolwiek innym komponencie, w którym chcesz go użyć.
Beau Smith
Dzięki za to! W moim konkretnym przypadku zaimportowałem przycisk material-ui z import IconButton from '@material-ui/core/IconButton';i użyłem go zamiast tego <button />i działało świetnie.
Dan Evans
1
@Melounek - Witam! Jeśli celem jest <a>wizualnie stylizowany tag HTML tak, aby wyglądał jak „przycisk”, to rozwiązanie Yes @ChaseJames pozwala to osiągnąć. Powyższe pytanie dotyczy sposobu użycia <button>elementu html, a nie pliku <a>.
Beau Smith
38

Dlaczego nie udekorować tagu linku tym samym CSS, co przycisk.

<Link 
 className="btn btn-pink"
 role="button"
 to="/"
 onClick={this.handleClick()}
> 
 Button1
</Link>
Ścigaj Jamesa
źródło
Zachowam to jako ostateczność, głównie dlatego, że mam zrobiony CSS dla wszystkich potrzebnych przycisków, ale dzięki za sugestię
Jose Rivera
Genialne rozwiązanie. Dla planu robię w ten sposób: <Link className = {[Classes.BUTTON, Classes.MINIMAL, Classes.ICON + "-" + IconNames.PLUS] .join ("")} to = {"/ link"}> Link </Link>
caiiiycuk
Nie możesz używać stanów włączonych / wyłączonych na fałszywym przycisku.
maco
16

Jeśli używasz react-router-domi material-uimożesz użyć ...

import { Link } from 'react-router-dom'
import Button from '@material-ui/core/Button';

<Button component={Link} to="/open-collective">
  Link
</Button>

Możesz przeczytać więcej tutaj .

Inam Ul Huq
źródło
To rozwiązanie nie będzie działać z TS, ponieważ topodpórka Linkjest obowiązkowa.
katalog
11

Można użyć useHistory haka ponieważ reagują-Router v5.1.0 .

useHistoryHak daje dostęp do instancji historii, które można wykorzystać do nawigacji.

import React from 'react'
import { useHistory } from 'react-router'

export default function SomeComponent() {
  const { push } = useHistory()
  ...
  <button
    type="button"
    onClick={() => push('/some-link')}
  >
    Some link
  </button>
  ...
}
SandroMarques
źródło
Czy możesz wcisnąć „jakiś link” do funkcji?
Rushino
W 2020 roku to nie działa. useHistory ma wartość null w mojej wersji React
bikeman868
7

Używam routera i <Button />. Nie <Link />

<Button onClick={()=> {this.props.history.replace('/mypage')}}>
   HERE
</Button>
Alan
źródło
1
Myślę, że powinno to być domyślne rozwiązanie, ale może niektóre szczegóły są dla mnie stracone? DOWOLNY komponent / węzeł / element, który obsługuje, onClick={ () => navigateTo(somePath) }może stosować to podejście. Czy używasz Redux i import {push} from 'connected-react-router'czy po prostu history.push(lub zamień), jak w Twojej odpowiedzi.
Thomas Fauskanger
6

⚠️ Nie, zagnieżdżanie html buttonw html a(lub odwrotnie) nie jest prawidłowym html

Raphael Rafatpanah
źródło
5
Spróbowałem tego i otrzymałem przycisk z małym klikalnym linkiem pośrodku, który spełniał swoją funkcję. Jednak kliknięcie w dowolnym innym miejscu przycisku, poza bezpośrednim linkiem, nic nie dało.
Jose Rivera
Możesz użyć CSS do stylizacji przycisku, aby upewnić się, że ma prawidłowy rozmiar. Na przykład ustawienie to widthi height.
Raphael Rafatpanah
2
Możesz używać stylów wbudowanych w ten sam sposób w przypadku tagu przycisku. Możesz też użyć jednej z wielu bibliotek „css in JS”. Wolę styled-components. github.com/styled-components/styled-components
Raphael Rafatpanah
1
Zadziałało z Twoją zaktualizowaną odpowiedzią. Dziękuję bardzo!
Jose Rivera
5
To nie jest poprawne ... Powinieneś owinąć przycisk, a nie link 😱
bensampaio
6

Dla każdego, kto szuka rozwiązania wykorzystującego React 16.8+ (hooks) i React Router 5:

Możesz zmienić trasę za pomocą przycisku z następującym kodem:

<button onClick={() => props.history.push("path")}>

React Router zapewnia pewne właściwości dla twoich komponentów, w tym funkcję push () w historii, która działa podobnie jak element <Link to = 'path'>.

Nie musisz opakowywać swoich komponentów komponentem wyższego rzędu „withRouter”, aby uzyskać dostęp do tych właściwości.

pflevy
źródło
To działa dobrze dla mnie; chociaż nie jestem pewien, co z tym rozwiązaniem jest specyficzne dla React 16.8+ lub hooków. Myślę, że jesteś w dobrej formie, o ile używasz BrowserRouter(w oparciu o HTML history API) zamiast HashRouter.
pglezen
5

Aktualizacja dla React Router w wersji 6:

Różne odpowiedzi tutaj są jak oś czasu ewolucji routera reakcji 🙂

Korzystając z najnowszych hooków z react-router v6, można to teraz łatwo zrobić za pomocą useNavigatehooka.

import { useNavigate } from 'react-router-dom'      

function MyLinkButton() {
  const navigate = useNavigate()
  return (
      <button onClick={() => navigate("/home")}>
        Go Home
      </button>
  );
}
JM Rossy
źródło
wersja 6 nie jest jeszcze dostępna iz tego powodu ta odpowiedź jest myląca. najnowszy od tego komentarza to 5.2.0.
davidawad
wersja 6 jest obecnie dostępna w wersji beta i jest używana w niektórych projektach. Zobacz kartę Wersje tutaj: npmjs.com/package/react-router
JM Rossy
3

Dzięki stylowym komponentom można to łatwo osiągnąć

Najpierw zaprojektuj stylizowany przycisk

import styled from "styled-components";
import {Link} from "react-router-dom";

const Button = styled.button`
  background: white;
  color:red;
  font-size: 1em;
  margin: 1em;
  padding: 0.25em 1em;
  border: 2px solid red;
  border-radius: 3px;
`
render(
    <Button as={Link} to="/home"> Text Goes Here </Button>
);

sprawdź stronę główną stylizowanego komponentu, aby uzyskać więcej

Obed
źródło
1

Wiele rozwiązań skupiało się na komplikowaniu rzeczy.

Korzystanie z withRouter to naprawdę długie rozwiązanie dla czegoś tak prostego jak przycisk, który prowadzi do innego miejsca w aplikacji.

Jeśli wybierasz się do SPA (aplikacja jednostronicowa), najłatwiejszą odpowiedzią, jaką znalazłem, jest użycie z odpowiednikiem className przycisku.

Zapewnia to utrzymanie udostępnionego stanu / kontekstu bez ponownego ładowania całej aplikacji, tak jak ma to miejsce w przypadku

import { NavLink } from 'react-router-dom'; // 14.6K (gzipped: 5.2 K)

// Where link.{something} is the imported data
<NavLink className={`bx--btn bx--btn--primary ${link.className}`} to={link.href} activeClassName={'active'}>
    {link.label}
</NavLink>

// Simplified version:
<NavLink className={'bx--btn bx--btn--primary'} to={'/myLocalPath'}>
    Button without using withRouter
</NavLink>
Dz 7, siedem
źródło
To nie zadziałało dla mnie. Styl hove przycisku zostaje utracony v_v.
sbstnssndn
Być może Twoje style zawisu są zbyt restrykcyjne? Czy są przypisane do button.myClassName? Usuń przycisk z selektora stylu. Lub rozszerz go w scss.
Acts