Обгортання посилання маршрутизатора з реакцією в кнопку html


108

Використання запропонованого методу: Це результат: Посилання на кнопку , Код між рядками коментарів

Мені було цікаво, чи є спосіб обернути Linkелемент із тегу 'react-router'HTML buttonза допомогою реакції.

В даний час у мене є Linkкомпоненти для навігації сторінками в моєму додатку, але я хотів би встановити цю функцію у свої кнопки HTML.

введіть тут опис зображення введіть тут опис зображення

Відповіді:


165

Хоча це відображатиметься у веб-браузері, пам’ятайте, що:
⚠️ Вкладання html buttonу html a(або навпаки) не є дійсним html ⚠️. Якщо ви хочете зберегти свою HTML-семантику для читання з екрана, скористайтеся іншим підходом.

Загортайте навпаки, і ви отримаєте оригінальну кнопку з прикріпленим посиланням. Ніяких змін CSS не потрібно.

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

Тут є кнопка HTML. Він також застосовується до компонентів, імпортованих із сторонніх бібліотек, таких як Semantic-UI-React .

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

1
Дякую, простий та робочий, тоді як css-рішення @ChaseJames не працює. Можливо, там чогось не вистачає. Але я використовую bootstrap; import { Button } from 'react-bootstrap';.
— Stefano Scarpanti

3
Під час вкладки по документу ви переходите на прив'язку, а потім до кнопки окремо. Щоб цього уникнути, додайте tabindex = "- 1" до елемента Link. Посилання все одно буде переходити (принаймні у Firefox ...), коли кнопка активується натисканням клавіші enter.
— трембі

4
Як відомо, Link створює тег <a href="">прив’язки, а прив’язка не може містити тег кнопок.
— тахер

4
Хоча це, здається, працює, це семантично помилково (і неприпустимо в HTML 5). Див. Чи можу я вкласти елемент <button> всередину <a> за допомогою HTML5?
— imgx64

Якщо ви, наприклад, вимкнете кнопку, натискання кнопки все одно спрацює. Насправді немає жодної причини використовувати це хакерське рішення порівняно з history.pushваріантом
— Бурак,

113

LinkButton компонент - рішення для React Router v4

Спочатку примітка про багато інших відповідей на це питання.

Вкладений <button>і <a>не дійсний html. ⚠️

Будь-яка відповідь тут, яка пропонує вкласти html buttonу Linkкомпонент React Router (або навпаки), буде відображатися у веб-браузері, але вона не є семантичною, доступною чи дійсним html:

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

☝ Клацніть, щоб перевірити цю розмітку за допомогою validator.w3.org ☝

Це може призвести до проблем із макетом / стилем, оскільки кнопки зазвичай не розміщуються всередині посилань.


Використання <button>тегу html з <Link>компонентом React Router .

Якщо вам потрібен лише buttonтег html ...

<button>label text</button>

… Тоді ось правильний спосіб отримати кнопку, яка працює як Linkкомпонент React Router …

Використовуйте React Router withRouter HOC, щоб передати ці компоненти своєму компоненту:

  • history
  • location
  • match
  • staticContext

LinkButton компонент

Ось LinkButtonкомпонент для копіювання / пасти :

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

Потім імпортуйте компонент:

import LinkButton from '/components/LinkButton'

Використовуйте компонент:

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

Якщо вам потрібен метод onClick:

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

Оновлення: Якщо ви шукаєте інший варіант розваг, який стане доступним після написання вище, перевірте цей хук useRouter .


13
Це має бути прийнятою відповіддю. Усі інші відповіді: IMHO - хакі та можуть дати несподівані результати. Дякую!
— Кайл

Чи буде використання компонента всередині <div> .. </divелемента App.js?
— DJ2,

@ DJ2 - Так, або в будь-якому іншому компоненті, в якому ти хочеш його використовувати.
— Бо Сміт,

Дякую за це! У моєму конкретному випадку використання я імпортував кнопку material-ui з import IconButton from '@material-ui/core/IconButton';і використовував її замість, <button />і вона чудово працювала.
— Ден Еванс

1
@Melounek - Привіт! Якщо метою є <a>тег html, візуально оформлений так, щоб виглядати як "кнопка", тоді рішення @ChaseJames досягає цього. Запитання вище задає питання, як використовувати <button>елемент html, а не файл <a>.
— Beau Smith

37

Чому б просто не прикрасити тег посилання тим самим css, що і кнопка.

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

Я буду тримати це як крайній засіб, головним чином тому, що я зробив CSS для всіх потрібних мені кнопок, але дякую за пропозицію
— Хосе Рівера,

Блискуче рішення. Для проекту я роблю таким чином: <Link className = {[Classes.BUTTON, Classes.MINIMAL, Classes.ICON + "-" + IconNames.PLUS] .join ("")} to = {"/ link"}> Посилання </Link>
— caiiiycuk,

13

Якщо ви використовуєте react-router-domі material-uiможете використовувати ...

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

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

Детальніше ви можете прочитати тут .


Це рішення не буде працювати з TS, оскільки toпідтримка Linkобов’язкова.
— каталог

Це працює як шарм, дякую
— Педро Сільва,

10

Ви можете використовувати useHistory хук з реакційного маршрутизатора v5.1.0 .

useHistoryКрюк дає вам доступ до примірника історії , які ви можете використовувати для навігації.

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

Чи можете ви натиснути "деяке посилання" на функцію?
— Рушино

У 2020 році це не працює для мене. useHistory є нульовим у моїй версії React
— bikeman868

7

Я використовую маршрутизатор і <Button />. Ні <Посилання />

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

1
Я думаю, що це має бути рішенням за замовчуванням, але, можливо, деякі деталі для мене втрачені? БУДЬ-ЯКИЙ компонент / вузол / елемент, що підтримує, onClick={ () => navigateTo(somePath) }може використовувати цей підхід. Чи використовуєте redux і import {push} from 'connected-react-router'чи просто history.push(або замінюєте), як у вашій відповіді.
— Томас Фаускангер

6

5
Тож я спробував це, і що я отримав - це кнопка з невеликим посиланням, що можна натиснути в центрі, яка виконувала свою функцію. Однак натискання в будь-якому місці кнопки, але пряме посилання нічого не робило.
— Хосе Рівера

Ви можете використовувати CSS для стилізації кнопки, щоб переконатися, що вона правильно розмірена. Наприклад, встановивши це widthі height.
— Рафаель Рафатпанах

2
Ви можете використовувати вбудовані стилі так само для тегу кнопки. Або ви можете скористатися однією з багатьох бібліотек "css in JS". Я віддаю перевагу styled-components. github.com/styled-components/styled-components
— Рафаель Рафатпанах

1
Це спрацювало з вашою оновленою відповіддю. Дуже дякую!
— Хосе Рівера,

5
Це неправильно ... Вам слід обернути кнопку, а не посилання 😱
— bensampaio

6

Для тих, хто шукає рішення за допомогою React 16.8+ (гачки) та React Router 5:

Ви можете змінити маршрут за допомогою кнопки з таким кодом:

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

React Router надає деякі реквізити для ваших компонентів, включаючи функцію push () в історії, яка працює майже так само, як елемент <Link to = 'path'>.

Вам не потрібно обертати ваші компоненти компонентом вищого порядку "withRouter", щоб отримати доступ до цих реквізитів.


Для мене це чудово працює; хоча я не впевнений, що з цим рішенням стосується React 16.8+ або хуків. Я думаю, ви в хорошій формі з цим, поки ви використовуєте BrowserRouter(на основі API історії HTML) замість HashRouter.
— pglezen

3

Завдяки стильовим компонентам цього можна легко досягти

Спочатку розробіть стилізовану кнопку

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

перевірте будинок стильового компонента, щоб дізнатись більше


3

Оновлення для React Router версії 6:

Різні відповіді тут схожі на часову шкалу розвитку реакційного маршрутизатора 🙂

Використовуючи найновіші гачки від response-router v6, тепер це можна легко зробити за допомогою useNavigateгачка.

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

function MyLinkButton() {
  const navigate = useNavigate()
  return (
      <button onClick={() => navigate("/home")}>
        Go Home
      </button>
  );
}

1

Багато рішень зосереджено на ускладненні речей.

Використання withRouter - це дійсно довге рішення для чогось такого простого, як кнопка, яка веде десь у додатку.

Якщо ви йдете на SPA (односторінковий додаток), найпростішою відповіддю, яку я знайшов, є використання з еквівалентним класом Імені кнопки.

Це гарантує, що ви підтримуєте спільний стан / контекст, не перезавантажуючи всю програму, як це було зроблено

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>

Це не спрацювало для мене. Стиль наведення кнопки губиться v_v.
— sbstnssndn

Можливо, ваші стилі наведення занадто обмежувальні? Вони призначені button.myClassName? Кнопка "Видалити" із селектора стилів. Або розширити його в scss.
— Acts7, Сім
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.