Bao bọc một Liên kết bộ định tuyến phản ứng trong một nút html


108

Sử dụng phương pháp gợi ý: Đây là kết quả: Một liên kết trong nút , Mã ở giữa các dòng nhận xét

Tôi đã tự hỏi liệu có cách nào để bao bọc một Linkphần tử 'react-router'trong buttonthẻ HTML bằng cách sử dụng phản ứng không.

Tôi hiện có Linkcác thành phần để điều hướng các trang trong ứng dụng của mình, nhưng tôi muốn ánh xạ chức năng đó tới các nút HTML của mình.

nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây

Câu trả lời:


165

Trong khi điều này sẽ hiển thị trong trình duyệt web, hãy lưu ý rằng:
⚠️ Việc lồng một html buttonvào một html a(hoặc ngược lại) không phải là html hợp lệ ⚠️. Nếu bạn muốn giữ ngữ nghĩa html của mình cho trình đọc màn hình, hãy sử dụng một cách tiếp cận khác.

Làm theo cách ngược lại và bạn sẽ có được nút ban đầu có đính kèm Liên kết. Không cần thay đổi CSS.

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

Nút đây là nút HTML. Nó cũng có thể áp dụng cho các thành phần được nhập từ thư viện của bên thứ ba như Semantic-UI-React .

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

1
Cảm ơn, đơn giản và hoạt động, trong khi giải pháp css của @ChaseJames không hoạt động. Có lẽ còn thiếu một cái gì đó. Nhưng tôi đang sử dụng bootstrap; import { Button } from 'react-bootstrap';.
Stefano Scarpanti

3
Khi lướt qua tài liệu, bạn sẽ chuyển tab đến anchor, sau đó đến nút riêng biệt. Để tránh điều này, hãy thêm tabindex = "- 1" vào phần tử Liên kết. Liên kết sẽ vẫn được theo dõi (ít nhất là trong Firefox ...) khi nút được kích hoạt bằng cách nhấn enter.
run rẩy vào

4
Như bạn đã biết, Link tạo thẻ <a href="">neo và thẻ neo không được chứa thẻ nút.
taher

4
Mặc dù điều này có vẻ hiệu quả, nhưng nó sai về mặt ngữ nghĩa (và không hợp lệ trong HTML 5). Xem Tôi có thể lồng phần tử <button> bên trong <a> bằng HTML5 không?
imgx64 Ngày

Ví dụ: nếu bạn làm cho nút của mình bị vô hiệu hóa, việc nhấp vào nút sẽ vẫn hoạt động. Thực sự không có lý do gì để sử dụng giải pháp hacky này khi so sánh với history.pushtùy chọn
Burak

113

LinkButton component - giải pháp cho React Router v4

Đầu tiên, một lưu ý về nhiều câu trả lời khác cho câu hỏi này.

⚠️ Làm tổ <button><a>html không hợp lệ. ⚠️

Bất kỳ câu trả lời nào ở đây gợi ý lồng một html buttontrong Linkthành phần Bộ định tuyến React (hoặc ngược lại) sẽ hiển thị trong trình duyệt web, nhưng nó không phải là html có ngữ nghĩa, có thể truy cập hoặc hợp lệ:

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

Nhấp để xác thực đánh dấu này với validator.w3.org

Điều này có thể dẫn đến các vấn đề về bố cục / kiểu dáng vì các nút thường không được đặt bên trong các liên kết.


Sử dụng <button>thẻ html với <Link>thành phần React Router .

Nếu bạn chỉ muốn một buttonthẻ html …

<button>label text</button>

… Sau đó, đây là cách phù hợp để có được một nút hoạt động giống như Linkthành phần của React Router …

Sử dụng React Router's withRouter HOC để chuyển các đạo cụ này đến thành phần của bạn:

  • history
  • location
  • match
  • staticContext

LinkButton thành phần

Đây là một LinkButtonthành phần để bạn sao chép / 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)

Sau đó nhập thành phần:

import LinkButton from '/components/LinkButton'

Sử dụng thành phần:

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

Nếu bạn cần một phương pháp onClick:

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

Cập nhật: Nếu bạn đang tìm kiếm một tùy chọn thú vị khác được cung cấp sau khi phần trên được viết, hãy xem useRouter hook này .


13
Đây phải là câu trả lời được chấp nhận. Tất cả các câu trả lời khác là, IMHO, hack và có thể cung cấp kết quả bất ngờ. Cảm ơn bạn!
Kyle

Việc sử dụng thành phần sẽ đi vào bên trong <div> .. </divphần tử của App.js?
DJ2

@ DJ2 - Vâng, hoặc trong bất kỳ thành phần khác mà bạn muốn sử dụng nó trong.
Beau Smith

Cám ơn vì cái này! Trong trường hợp sử dụng cụ thể của tôi, tôi đã nhập một nút material-ui với import IconButton from '@material-ui/core/IconButton';và sử dụng nút đó thay vì <button />và nó hoạt động rất tốt.
Dan Evans

1
@Melounek - Xin chào! Nếu mục tiêu là có <a>thẻ html được tạo kiểu trực quan để trông giống như một "nút", thì có giải pháp @ChaseJames đạt được điều này. Câu hỏi ở trên hỏi cách sử dụng một <button>phần tử html, không phải một <a>.
Beau Smith

37

Tại sao không chỉ trang trí thẻ liên kết với cùng một css như một nút.

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

Tôi sẽ giữ điều này như một phương sách cuối cùng chủ yếu là bởi vì tôi đã CSS làm cho tất cả các nút mà tôi cần nhưng nhờ đề nghị
Jose Rivera

Giải pháp tuyệt vời. Đối với bản thiết kế, tôi thực hiện theo cách này: <Link className = {[Classes.BUTTON, Classes.MINIMAL, Classes.ICON + "-" + IconNames.PLUS] .join ("")} to = {"/ link"}> Liên kết </Link>
caiiiycuk

13

Nếu bạn đang sử dụng react-router-dommaterial-uibạn có thể sử dụng ...

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

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

Bạn có thể đọc thêm ở đây .


Giải pháp này sẽ không hoạt động với TS vì toviệc bật Linklà bắt buộc.
thư mục

Điều này hoạt động như một sự quyến rũ, cảm ơn
Pedro Silva

11

Bạn có thể sử dụng useHistory hook kể từ react-router v5.1.0 .

Cái useHistorymóc cung cấp cho bạn quyền truy cập vào phiên bản lịch sử mà bạn có thể sử dụng để điều hướng.

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

Bạn có thể đẩy "some-link" vào chức năng không?
Rushino

Vào năm 2020, điều này không hiệu quả với tôi. useHistory không có trong phiên bản React của tôi
bikeman868

7

Tôi sử dụng Bộ định tuyến và <Nút />. Không <Liên kết />

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

1
Tôi nghĩ rằng đây nên là giải pháp mặc định, nhưng có lẽ một số chi tiết bị mất đối với tôi? BẤT KỲ thành phần / nút / phần tử nào hỗ trợ đều onClick={ () => navigateTo(somePath) }có thể sử dụng phương pháp này. Cho dù sử dụng redux và import {push} from 'connected-react-router'hoặc chỉ history.push(hoặc thay thế) như trong câu trả lời của bạn.
Thomas Fauskanger

6

5
Vì vậy, tôi đã thử điều này và những gì tôi nhận được là một nút với một liên kết nhỏ có thể nhấp được ở trung tâm phục vụ chức năng của nó. Tuy nhiên nhấp vào bất kỳ nơi nào khác trên nút nhưng liên kết trực tiếp không làm gì cả.
Jose Rivera

Bạn có thể sử dụng CSS để tạo kiểu cho nút để đảm bảo rằng nó có kích thước chính xác. Ví dụ, đặt nó widthheight.
Raphael Rafatpanah

2
Bạn có thể sử dụng các kiểu nội tuyến theo cách tương tự cho thẻ nút. Hoặc bạn có thể sử dụng một trong nhiều thư viện "css in JS". Tôi thích hơn styled-components. github.com/styled-components/styled-components
Raphael Rafatpanah

1
Nó hoạt động với câu trả lời cập nhật của bạn. Cảm ơn bạn rất nhiều!
Jose Rivera

5
Đây không phải là chính xác ... Bạn nên quấn vào nút, không phải là liên kết 😱
bensampaio

6

Đối với bất kỳ ai đang tìm kiếm giải pháp sử dụng React 16.8+ (hooks) và React Router 5:

Bạn có thể thay đổi tuyến đường bằng cách sử dụng một nút có mã sau:

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

React Router cung cấp một số đạo cụ cho các thành phần của bạn, bao gồm cả hàm push () trên history hoạt động khá giống với phần tử <Link to = 'path'>.

Bạn không cần phải bọc các thành phần của mình bằng Thành phần thứ tự cao hơn "withRouter" để có quyền truy cập vào các đạo cụ đó.


Cái này làm việc tốt cho tôi; mặc dù tôi không chắc những gì về giải pháp này dành riêng cho React 16.8+ hoặc hook. Tôi nghĩ rằng bạn đang ở trong tình trạng tốt với điều này miễn là bạn sử dụng BrowserRouter(dựa trên API lịch sử HTML) thay vì HashRouter.
pglezen

3

Với các thành phần được tạo kiểu, điều này có thể dễ dàng đạt được

Đầu tiên Thiết kế một nút theo kiểu

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

kiểm tra trang chủ của thành phần được tạo kiểu để biết thêm


3

Cập nhật cho React Router phiên bản 6:

Các câu trả lời khác nhau ở đây giống như dòng thời gian về sự phát triển của bộ định tuyến phản ứng 🙂

Sử dụng hook mới nhất từ ​​react-router v6, điều này hiện có thể được thực hiện dễ dàng với useNavigatehook.

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

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

1

Nhiều giải pháp đã tập trung vào việc làm phức tạp mọi thứ.

Sử dụng withRouter là một giải pháp thực sự lâu dài cho những thứ đơn giản như một nút liên kết đến một nơi khác trong Ứng dụng.

Nếu bạn đang sử dụng SPA (ứng dụng một trang), câu trả lời dễ nhất mà tôi tìm thấy là sử dụng với className tương đương của nút.

Điều này đảm bảo bạn đang duy trì trạng thái / ngữ cảnh được chia sẻ mà không cần tải lại toàn bộ ứng dụng của mình như được thực hiện với

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>

Điều này không hiệu quả với tôi. Phong cách hove của nút bị mất v_v.
sbstnssndn

Có lẽ phong cách di chuột của bạn quá hạn chế? Họ có được gán cho button.myClassName không? Xóa nút khỏi bộ chọn kiểu. Hoặc mở rộng nó trong scss.
Acts 7 Seven
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.