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>

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 .


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>

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 .


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

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>

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

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.


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>
  );
}

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


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>

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.