简体   繁体   English

在 html 按钮中包装 react-router 链接

[英]Wrapping a react-router Link in an html button

Using suggested method: This is the result: A link in the button , Code in between comment lines使用建议的方法:结果如下:按钮中的链接注释行之间的代码

I was wondering if there is a way to wrap a Link element from 'react-router' in an HTML button tag using react.我想知道是否有一种方法可以使用 react 将来自'react-router'Link元素包装在 HTML button标签中。

I currently have Link components to navigate pages in my app, but I would like to map that functionality to my HTML buttons.我目前有Link组件来导航我的应用程序中的页面,但我想 map 该功能到我的 HTML 按钮。

在此处输入图像描述 在此处输入图像描述

While this will render in a web browser, beware that:虽然这将在 Web 浏览器中呈现,但请注意:
⚠️ Nesting an html button in an html a (or vice-versa) is not valid html ⚠️. ⚠️ 在 html a嵌套 html button (反之亦然)是无效的 html ⚠️。 If you want to keep your html semantic to screen readers, use another approach.如果您想将 html 语义保留给屏幕阅读器,请使用另一种方法。

Do wrapping in the reverse way and you get the original button with the Link attached.以相反的方式包装,您将获得带有链接的原始按钮。 No CSS changes required.无需更改 CSS。

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

Here button is HTML button.这里的按钮是 HTML 按钮。 It is also applicable to the components imported from third party libraries like Semantic-UI-React .它也适用于从Semantic-UI-React等第三方库导入的组件。

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

LinkButton component - a solution for React Router v4 LinkButton组件 - React Router v4 的解决方案

First, a note about many other answers to this question.首先,关于这个问题的许多其他答案的说明。

⚠️ Nesting <button> and <a> is not valid html. ⚠️ 嵌套<button><a>不是有效的 html。 ⚠️ ⚠️

Any answer here which suggests nesting a html button in a React Router Link component (or vice-versa) will render in a web browser, but it is not semantic, accessible, or valid html:此处任何建议在 React Router Link组件中嵌套 html button (或反之亦然)的答案都将在 Web 浏览器中呈现,但它不是语义、可访问或有效的 html:

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

Click to validate this markup with validator.w3.org 单击以使用validator.w3.org 验证此标记

This can lead to layout/styling issues as buttons are not typically placed inside links.这可能会导致布局/样式问题,因为按钮通常不会放置在链接内。


Using an html <button> tag with React Router <Link> component.在 React Router <Link>组件中使用 html <button>标签。

If you only want an html button tag…如果你只想要一个 html button标签......

<button>label text</button>

…then, here's the right way to get a button that works like React Router's Link component… ……那么,这是获得一个像 React Router 的Link组件一样工作的按钮的正确方法……

Use React Router's withRouter HOC to pass these props to your component:使用 React Router 的withRouter HOC 将这些 props 传递给你的组件:

  • history
  • location
  • match
  • staticContext

LinkButton component LinkButton组件

Here's a LinkButton component for you to copy/ pasta :这是一个供您复制/面食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)

Then import the component:然后导入组件:

import LinkButton from '/components/LinkButton'

Use the component:使用组件:

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

If you need an onClick method:如果您需要一个 onClick 方法:

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

Update: If you're looking for another fun option made available after the above was written, check out this useRouter hook .更新:如果您正在寻找在编写上述内容后提供的另一个有趣选项,请查看此useRouter hook

Why not just decorate link tag with the same css as a button.为什么不使用与按钮相同的 css 来装饰链接标签。

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

If you are using react-router-dom and material-ui you can use ...如果您使用的是react-router-dommaterial-ui ,则可以使用 ...

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

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

You can read more here .您可以在此处阅读更多内容。

You can use useHistory hook since react-router v5.1.0 .react-router useHistory开始,您可以使用useHistory钩子

The useHistory hook gives you access to the history instance that you may use to navigate. useHistory挂钩使您可以访问可用于导航的历史记录实例。

import React from 'react'
import { useHistory } from 'react-router-dom'

export default function SomeComponent() {
  const { push } = useHistory()
  ...
  <button
    type="button"
    onClick={() => push('/some-link')}
  >
    Some link
  </button>
  ...
}

NOTE: be aware that this technique is not accessible like @ziz194 says in their comment注意:请注意,此技术无法像@ziz194 在他们的评论中所说的那样访问

this is not accessible though, as the button will not be a tag and thus it doesn't have link behaviours, like opening the link in a new page.但是这是不可访问的,因为按钮不是标签,因此它没有链接行为,例如在新页面中打开链接。 It is also not optimal for screen readers.它对于屏幕阅读器也不是最佳选择。

I use Router and < Button/>.我使用路由器和 < Button/>。 No < Link/>没有<链接/>

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

For anyone looking for a solution using React 16.8+ (hooks) and React Router 5:对于任何使用React 16.8+ (钩子)和 React Router 5 寻找解决方案的人:

You can change the route using a button with the following code:您可以使用带有以下代码的按钮更改路线:

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

React Router provides some props to your components, including the push() function on history which works pretty much like the < Link to='path' > element. React Router 为您的组件提供了一些道具,包括历史上push()函数,它的工作方式与 < Link to='path' > 元素非常相似。

You don't need to wrap your components with the Higher Order Component "withRouter" to get access to those props.你不需要用高阶组件“withRouter”包装你的组件来访问这些道具。

With styled components this can be easily achieved使用样式组件可以轻松实现

First Design a styled button首先设计一个样式按钮

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

check styled component's home for more检查样式组件的主页以获取更多信息

Update for React Router version 6: React Router 版本 6 的更新:

The various answers here are like a timeline of react-router's evolution 🙂这里的各种答案就像是 react-router 进化的时间线🙂

Using the latest hooks from react-router v6, this can now be done easily with the useNavigate hook.使用 react-router v6 的最新钩子,现在可以通过useNavigate钩子轻松完成。

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

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

Many of the solutions have focused on complicating things.许多解决方案都专注于使事情复杂化。

Using withRouter is a really long solution for something as simple as a button that links to somewhere else in the App.使用 withRouter 是一个非常长的解决方案,对于像链接到应用程序中其他地方的按钮这样简单的东西。

If you are going for SPA (single page application), the easiest answer I have found is to use with the button's equivalent className.如果您要使用 SPA(单页应用程序),我找到的最简单的答案是与按钮的等效类名一起使用。

This ensures you are maintaining shared state / context without reloading your entire app as is done with这可确保您保持共享状态/上下文,而无需像之前那样重新加载整个应用程序

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>

Using react-router-dom and a function使用react-router-dom和一个函数

In react, you can use react-router-dom by applying the useHistory call...在反应中,您可以通过应用useHistory调用来使用react-router-dom ...

- Firstly - 首先

import { useHistory } from 'react-router-dom';

- Secondly Inside your function...write a function to handle the button click - 其次在你的函数内部...编写一个函数来处理按钮点击

const handleButtonClick = () => {
    history.push('/YourPageLink')
  }

- Lastly - 最后

<button onClick={handleButtonClick} className="CSS">
   Button Text
</button>

I recommend that you utilize the component prop on the Link component.我建议您在Link组件上使用component属性。 Using this, you can have effectively any component behave as an a component from the perspective of React Rotuer.使用它,您可以有效地将任何组件从 React Rotuer 的角度视为a组件。 For instance, you can create your own "Button" component and then utilize this.例如,您可以创建自己的“按钮”组件,然后使用它。


const MyButton = () => {
    return <button>Do something with props, etc.</button>
}

<Link to="/somewhere" component={MyButton}>Potentially pass in text here</Link>
<Button component={Link} to="/dashboard" type="button">
    Click Me!
</Button>

As I searched through answers everyone was talking about the old versions of react-router-dom, so this might be useful answer for those who want to use the hooks in functional components.当我搜索答案时,每个人都在谈论旧版本的 react-router-dom,因此对于那些想要在功能组件中使用钩子的人来说,这可能是有用的答案。 As in the new version few hooks are changed and even the withRouter is not applicable you need to make a custom HOC.由于在新版本中很少更改挂钩,甚至 withRouter 也不适用,您需要制作自定义 HOC。

we can achieve it through functional components you can use your button and then describe onClick event to trigger to the next page through useNavigate hook.我们可以通过功能组件来实现,您可以使用您的按钮,然后通过 useNavigate 钩子描述 onClick 事件触发到下一页。

React-Router-Dom version 6 React-Router-Dom 版本 6


this is only possible in functional components as i am using hooks, if you want to use on class components then you can make hoc.这仅在功能组件中才有可能,因为我正在使用钩子,如果您想在类组件上使用,那么您可以制作 hoc。

import {Link, useNavigate} from 'react-router-dom';
function Home() {
you can pass your state like so:  navigate('/show',{state});
const toShowInfoPage=()=>{
navigate('/show');

  }


return(
<>


 /*you can use button as well or anything 
of your choice, but remember 
you have to pass the onClick event.
    */
 <a 
onClick={()=>{toShowInfoPage()}} 
style={{textDecoration:'none',
paddingRight:'20px',
color:'#187bcd',
cursor:'pointer'}}>


</>

)



}

To access useNavigate() with a class component you must either convert to a function component, or roll your own custom withRouter Higher Order Component to inject the "route props" like the withRouter HOC from react-router-dom v5.x did.要使用类组件访问 useNavigate(),您必须转换为函数组件,或者滚动您自己的自定义withRouter高阶组件以注入“路由道具”,就像react-router-dom v5.x 中的withRouter HOC 所做的那样。


This is just a general idea.这只是一个普遍的想法。 if you want to useNavigate Here's an example custom withRouter HOC:如果你想使用Navigate 这里有一个例子custom withRouter HOC:

const withRouter = WrappedComponent => props => {
  const params = useParams();
  // etc... other react-router-dom v6 hooks

  return (
    <WrappedComponent
      {...props}
      params={params}
      // etc...
    />
  );
};

And decorate the component with the new HOC.并用新的 HOC 装饰组件。

export default withRouter(Post);

This will inject a props for the class component.这将为类组件注入一个props

You can use the component prop: https://v5.reactrouter.com/web/api/Link/component-reactcomponent您可以使用component道具: https://v5.reactrouter.com/web/api/Link/component-reactcomponent

For example:例如:

<Link to="/login" component={({ navigate}) => <button onClick={navigate}>Login</button>} />

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM