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.