Einschließen eines React-Router-Links in eine HTML-Schaltfläche


100

Verwenden der vorgeschlagenen Methode: Dies ist das Ergebnis: Ein Link in der Schaltfläche , Code zwischen Kommentarzeilen

Ich habe mich gefragt, ob es eine Möglichkeit gibt, ein LinkElement mithilfe von "Reagieren" 'react-router'in ein HTML- buttonTag einzuschließen.

Ich habe derzeit LinkKomponenten zum Navigieren in Seiten in meiner App, möchte diese Funktionalität jedoch meinen HTML-Schaltflächen zuordnen.

Geben Sie hier die Bildbeschreibung ein Geben Sie hier die Bildbeschreibung ein

Antworten:


154


Beachten Sie Folgendes, während dies in einem Webbrowser gerendert wird : ⚠️ Das Verschachteln eines HTML-buttona Codes in einem HTML- Code (oder umgekehrt) ist kein gültiger HTML- Code. ⚠️ Wenn Sie Ihre HTML-Semantik für Screenreader beibehalten möchten, verwenden Sie einen anderen Ansatz.

Wenn Sie in umgekehrter Reihenfolge einwickeln, erhalten Sie die ursprüngliche Schaltfläche mit dem angehängten Link. Keine CSS-Änderungen erforderlich.

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

Hier ist die Schaltfläche HTML. Dies gilt auch für Komponenten, die aus Bibliotheken von Drittanbietern wie Semantic-UI-React importiert wurden .

 import { Button } from 'semantic-ui-react'
 ... 
 <Link to="/dashboard">
     <Button style={myStyle}>
        <p>Click Me!</p>
     </Button>
 </Link>

1
Danke, einfach und funktionierend, während die CSS-Lösung von @ChaseJames nicht funktioniert. Vielleicht fehlt da etwas. Aber ich benutze Bootstrap; import { Button } from 'react-bootstrap';.
Stefano Scarpanti

2
Wenn Sie durch das Dokument blättern, gelangen Sie zum Anker und dann separat zur Schaltfläche. Um dies zu vermeiden, fügen Sie dem Link-Element tabindex = "- 1" hinzu. Der Link wird weiterhin verfolgt (zumindest in Firefox ...), wenn die Schaltfläche durch Drücken der Eingabetaste aktiviert wird.
Tremby

4
Wie Sie wissen, erstellt Link ein Ankertag, <a href="">und das Ankertag darf kein Schaltflächen-Tag enthalten.
Taher

4
Dies scheint zwar zu funktionieren, ist jedoch semantisch falsch (und in HTML 5 ungültig). Siehe Kann ich mit HTML5 ein <button> -Element in einem <a> verschachteln?
imgx64

Wenn Sie beispielsweise Ihre Schaltfläche deaktivieren, funktioniert das Klicken auf die Schaltfläche weiterhin. Es gibt wirklich keinen Grund, diese hackige Lösung im Vergleich zu der history.pushOption zu verwenden
Burak

109

LinkButton Komponente - eine Lösung für React Router v4

Zunächst ein Hinweis zu vielen anderen Antworten auf diese Frage.

⚠️ Verschachtelung <button>und <a>ist kein gültiges HTML. ⚠️

Jede Antwort hier, die vorschlägt, ein HTML buttonin eine React Router- LinkKomponente zu verschachteln (oder umgekehrt), wird in einem Webbrowser gerendert, ist jedoch kein semantisches, zugängliches oder gültiges HTML:

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

Klicken Sie hier, um dieses Markup mit validator.w3.org zu validieren.

Dies kann zu Layout- / Stilproblemen führen, da Schaltflächen normalerweise nicht in Links platziert werden.


Verwenden eines HTML- <button>Tags mit der React Router- <Link>Komponente.

Wenn Sie nur ein HTML- buttonTag möchten ...

<button>label text</button>

… Dann ist hier der richtige Weg, um eine Schaltfläche zu erhalten, die wie die LinkKomponente von React Router funktioniert …

Verwenden Sie den WithRouter HOC von React Router , um diese Requisiten an Ihre Komponente zu übergeben:

  • history
  • location
  • match
  • staticContext

LinkButton Komponente

Hier ist eine LinkButtonKomponente zum Kopieren / Pasta :

// 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)

Importieren Sie dann die Komponente:

import LinkButton from '/components/LinkButton'

Verwenden Sie die Komponente:

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

Wenn Sie eine onClick-Methode benötigen:

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

Update: Wenn Sie nach einer anderen unterhaltsamen Option suchen, die nach dem Schreiben des oben genannten verfügbar gemacht wurde, sehen Sie sich diesen useRouter-Hook an .


13
Dies sollte die akzeptierte Antwort sein. Alle anderen Antworten sind meiner Meinung nach Hacks und können unerwartete Ergebnisse liefern. Danke dir!
Kyle

Würde die Verwendung der Komponente in das <div> .. </divElement von gehen App.js?
DJ2

@ DJ2 - Ja, oder in einer anderen Komponente, in der Sie es verwenden möchten.
Beau Smith

Danke dafür! In meinem speziellen Anwendungsfall habe ich einen Material-UI-Button mit importiert import IconButton from '@material-ui/core/IconButton';und stattdessen verwendet, <button />und es hat großartig funktioniert.
Dan Evans

1
@ Melounek - Hallo! Wenn das Ziel darin besteht, ein <a>HTML-Tag visuell so zu gestalten, dass es wie eine "Schaltfläche" aussieht, dann erreicht die @ ChaseJames-Lösung dies. In der obigen Frage wird gefragt, wie ein <button>HTML-Element verwendet werden soll, nicht ein <a>.
Beau Smith

37

Warum nicht einfach das Link-Tag mit dem gleichen CSS wie eine Schaltfläche dekorieren?

<Link 
 className="btn btn-pink"
 role="button"
 to="/"
 onClick={this.handleClick()}
> 
 Button1
</Link>

Ich werde dies als letzten Ausweg behalten, hauptsächlich, weil ich das CSS für alle Schaltflächen erledigt habe, die ich brauche, aber danke für den Vorschlag
Jose Rivera

Geniale Lösung. Für die Blaupause gehe ich folgendermaßen vor: <Link className = {[Classes.BUTTON, Classes.MINIMAL, Classes.ICON + "-" + IconNames.PLUS] .join ("")} to = {"/ link"}> Link </ Link>
caiiiycuk

10

Wenn Sie verwenden react-router-domund material-uiSie können verwenden ...

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

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

Sie können mehr lesen hier .


Diese Lösung funktioniert nicht mit TS, da die toAktivierung Linkobligatorisch ist.
Verzeichnis

9

Sie können useHistory Hook seit React-Router v5.1.0 verwenden .

Der useHistoryHook gibt Ihnen Zugriff auf die Verlaufsinstanz, mit der Sie navigieren können.

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

Können Sie "some-link" auf die Funktion drücken?
Rushino

7

Ich benutze Router und <Button />. Nein <Link />

<Button onClick={()=> {this.props.history.replace('/mypage')}}>
   HERE
</Button>

1
Ich denke, dies sollte die Standardlösung sein, aber vielleicht gehen mir einige Details verloren? JEDE Komponente / jeder Knoten / jedes Element, die / das unterstützt, onClick={ () => navigateTo(somePath) }könnte diesen Ansatz verwenden. Ob Sie Redux verwenden und import {push} from 'connected-react-router'oder nur history.push(oder ersetzen) wie in Ihrer Antwort.
Thomas Fauskanger

6

5
Also habe ich es versucht, und was ich bekam, war eine Schaltfläche mit einem kleinen anklickbaren Link in der Mitte, der seine Funktion erfüllte. Wenn Sie jedoch irgendwo anders auf die Schaltfläche klicken, aber der direkte Link nichts bewirkt.
Jose Rivera

Sie können die Schaltfläche mithilfe von CSS formatieren, um sicherzustellen, dass sie die richtige Größe hat. Zum Beispiel das Einstellen von widthund height.
Raphael Rafatpanah

2
Sie können Inline-Stile auf die gleiche Weise für das Schaltflächen-Tag verwenden. Oder Sie können eine der vielen "CSS in JS" -Bibliotheken verwenden. Ich bevorzuge styled-components. github.com/styled-components/styled-components
Raphael Rafatpanah

1
Es hat mit Ihrer aktualisierten Antwort funktioniert. Ich danke dir sehr!
Jose Rivera

5
Dies ist nicht korrekt ... Sie sollten den Knopf einwickeln, nicht den Link 😱
bensampaio

6

Für alle, die nach einer Lösung mit React 16.8+ (Hooks) und React Router 5 suchen :

Sie können die Route mit einer Schaltfläche mit dem folgenden Code ändern:

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

React Router bietet einige Requisiten für Ihre Komponenten, einschließlich der push () - Funktion im Verlauf, die dem Element <Link to = 'path'> ziemlich ähnlich ist.

Sie müssen Ihre Komponenten nicht mit der Komponente höherer Ordnung "withRouter" umschließen, um Zugriff auf diese Requisiten zu erhalten.


Das funktioniert gut für mich; Ich bin mir jedoch nicht sicher, was mit dieser Lösung für React 16.8+ oder Hooks spezifisch ist. Ich denke, Sie sind damit in guter Verfassung, solange Sie BrowserRouter(basierend auf der HTML-Verlaufs-API) anstelle von verwenden HashRouter.
pglezen

3

Mit gestalteten Komponenten kann dies leicht erreicht werden

Entwerfen Sie zuerst einen gestalteten Knopf

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

überprüfen Heim gestylten Komponente für mehr


1

Viele der Lösungen haben sich darauf konzentriert, Dinge zu komplizieren.

Die Verwendung von withRouter ist eine sehr lange Lösung für etwas so Einfaches wie eine Schaltfläche, die auf eine andere Stelle in der App verweist.

Wenn Sie sich für SPA (Single Page Application) entscheiden, ist die einfachste Antwort, die ich gefunden habe, die Verwendung mit dem entsprechenden Klassennamen der Schaltfläche.

Dies stellt sicher, dass Sie den gemeinsamen Status / Kontext beibehalten, ohne Ihre gesamte App neu zu laden

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>

Das hat bei mir nicht funktioniert. Der Hove-Stil der Schaltfläche geht verloren v_v.
sbstnssndn

Vielleicht sind Ihre Schwebestile zu restriktiv? Sind sie button.myClassName zugeordnet? Entfernen Sie die Schaltfläche aus der Stilauswahl. Oder erweitern Sie es in scss.
Acts7Seven
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.