【问题标题】:Wrapping a react-router Link in an html button将 react-router 链接包装在 html 按钮中
【发布时间】:2017-07-16 17:44:09
【问题描述】:

使用建议的方法: This is the result: A link in the button, Code in between comment lines

我想知道是否有办法使用 react 将 'react-router' 中的 Link 元素包装到 HTML button 标记中。

我目前有 Link 组件来导航我的应用程序中的页面,但我想将该功能映射到我的 HTML 按钮。

【问题讨论】:

    标签: html reactjs button hyperlink router


    【解决方案1】:

    虽然这将在网络浏览器中呈现,但请注意:
    ⚠️Nesting an html button in an html a (or vice-versa) is not valid 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>
    

    【讨论】:

    • 谢谢,简单且有效,而 @ChaseJames 的 css 解决方案不起作用。也许有什么东西不见了。但我正在使用引导程序; import { Button } from 'react-bootstrap';.
    • 在文档中切换时,您将切换到锚点,然后分别切换到按钮。为避免这种情况,请将 tabindex="-1" 添加到 Link 元素。当按下回车键激活按钮时,该链接仍将被跟踪(至少在 Firefox 中...)。
    • 如你所知,Link创建锚标签&lt;a href=""&gt;,锚标签不能包含按钮标签。
    • 虽然这似乎可行,但它在语义上是错误的(在 HTML 5 中无效)。见Can I nest a <button> element inside an <a> using HTML5?
    • 例如,如果您禁用按钮,单击该按钮仍然有效。与 history.push 选项相比,真的没有理由使用这个 hacky 解决方案
    【解决方案2】:

    LinkButton 组件 - React Router v4 的解决方案

    首先,关于这个问题的许多其他答案的注释。

    ⚠️ 嵌套 &lt;button&gt;&lt;a&gt; 不是有效的 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

    这可能会导致布局/样式问题,因为按钮通常不会放置在链接内。


    使用带有 React Router &lt;Link&gt; 组件的 html &lt;button&gt; 标签。

    如果你只想要一个 html button 标签……

    <button>label text</button>
    

    ...那么,这里是获得像 React Router 的 Link 组件一样工作的按钮的正确方法...

    使用 React Router 的 withRouter HOC 将这些 props 传递给您的组件:

    • history
    • location
    • match
    • staticContext

    LinkButton组件

    这里有一个LinkButton 组件供你复制/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)
    

    然后导入组件:

    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 hook

    【讨论】:

    【解决方案3】:

    为什么不使用与按钮相同的 CSS 来装饰链接标签。

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

    【讨论】:

    • 我将把它作为最后的手段,主要是因为我已经为我需要的所有按钮完成了 CSS,但感谢您的建议
    • 出色的解决方案。对于蓝图,我这样做: 链接
    • 你不能在假按钮上使用启用/禁用状态。
    • 这可能是最好的方法,因为导航通常应该使用链接语义,即&lt;a/&gt; 标签。应该注意的是,简单地将为&lt;button/&gt; 设计的现有 CSS 类应用于&lt;a/&gt; 可能会导致样式损坏。原因是这些元素在 CSS 行为方面根本不同,请参阅this question。就我而言,我需要先重构样式才能应用此解决方案。
    【解决方案4】:

    如果您使用的是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>
    

    您可以阅读更多here

    【讨论】:

    • 此解决方案不适用于 TS,因为 Link 上的 to 属性是强制性的。
    【解决方案5】:

    您可以使用useHistory hook,因为react-router v5.1.0

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

    注意:请注意,这种方法可以回答问题,但无法像 @ziz194 在他们的评论中所说的那样访问

    但这是不可访问的,因为按钮不是标签,因此它没有链接行为,例如在新页面中打开链接。它也不是屏幕阅读器的最佳选择。

    【讨论】:

    【解决方案6】:

    我使用路由器和。没有

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

    【讨论】:

    • 我认为这应该是默认解决方案,但也许我丢失了一些细节?支持onClick={ () =&gt; navigateTo(somePath) }任何 组件/节点/元素都可以使用这种方法。无论是使用 redux 和 import {push} from 'connected-react-router' 还是只使用 history.push (或替换),就像你的答案一样。
    • 此解决方案无法访问,您无法使用此解决方案在新页面中打开链接。
    【解决方案7】:

    对于寻求使用 React 16.8+(钩子)和 React Router 5 的解决方案的任何人:

    您可以使用带有以下代码的按钮更改路线:

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

    React Router 为您的组件提供一些道具,包括 history 上的 push() 函数,它的工作原理与 元素。

    您无需使用高阶组件“withRouter”包装您的组件即可访问这些道具。

    【讨论】:

    • 这对我来说很好;虽然我不确定这个解决方案是否特定于 React 16.8+ 或钩子。我认为只要您使用 BrowserRouter(基于 HTML 历史 API)而不是 HashRouter,您的状态就很好。
    • 非链接元素的点击导航很糟糕。您无法像使用 Link 一样进行交互,因此没有“在新标签页中打开”功能。
    【解决方案8】:

    React Router 版本 6 更新:

    这里的各种答案就像是react-router进化的时间线?

    使用 react-router v6 的最新钩子,现在可以通过 useNavigate 钩子轻松完成。

    import { useNavigate } from 'react-router-dom'      
    
    function MyLinkButton() {
      const navigate = useNavigate()
      return (
          <button onClick={() => navigate("/home")}>
            Go Home
          </button>
      );
    }
    

    【讨论】:

    • 版本 6 尚不可用,因此这个答案令人困惑。此评论的最新版本是 5.2.0。
    • 第 6 版目前处于测试阶段,并在某些项目中使用。请在此处查看版本标签:npmjs.com/package/react-router
    【解决方案9】:

    使用样式化组件可以轻松实现

    首先设计一个样式按钮

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

    查看styled component's home了解更多信息

    【讨论】:

      【解决方案10】:

      【讨论】:

      • 所以我尝试了这个,我得到的是一个按钮,中间有一个可点击的小链接,起到了它的作用。然而,点击按钮上的其他任何地方,但直接链接什么也没做。
      • 您可以使用 CSS 设置按钮的样式以确保其大小正确。例如,设置为widthheight
      • 您可以使用与按钮标签相同的方式使用内联样式。或者,您可以使用众多“JS 中的 css”库之一。我更喜欢styled-componentsgithub.com/styled-components/styled-components
      • 它适用于您更新的答案。非常感谢!
      • 这不正确...您应该包装按钮,而不是链接?
      【解决方案11】:
      <Button component={Link} to="/dashboard" type="button">
          Click Me!
      </Button>
      

      【讨论】:

      • 虽然此代码可能会回答问题,但提供有关它如何和/或为什么解决问题的额外上下文将提高​​答案的长期价值。您可以在帮助中心找到更多关于如何写好答案的信息:stackoverflow.com/help/how-to-answer。祝你好运?
      【解决方案12】:

      许多解决方案都专注于使事情复杂化。

      对于像链接到应用程序中其他位置的按钮这样简单的事情,使用 withRouter 是一个非常长的解决方案。

      如果您要参加 S.P.A. (单页应用程序),我找到的最简单的答案是使用按钮的等效类名。

      这可确保您保持共享状态/上下文,而无需像使用

      那样重新加载整个应用程序
      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>
      

      【讨论】:

      • 这对我不起作用。按钮的hove样式丢失了v_v。
      • 也许您的悬停样式过于严格?它们是否分配给 button.myClassName?从样式选择器中删除按钮。或者在 scss 中扩展。
      【解决方案13】:

      我建议您在 Link 组件上使用 component 属性。使用它,您可以有效地让任何组件从 React Rotuer 的角度表现为a 组件。例如,您可以创建自己的“按钮”组件,然后使用它。

      
      const MyButton = () => {
          return <button>Do something with props, etc.</button>
      }
      
      <Link to="/somewhere" component={MyButton}>Potentially pass in text here</Link>
      

      【讨论】:

      • 我同意,这就是它的用途。我个人会这样写:&lt;Link to="/somewhere" component={c =&gt; &lt;button {...c} /&gt;}&gt;Pass in text here&lt;/Link&gt;
      【解决方案14】:

      使用react-router-dom 和一个函数

      在反应中,您可以通过应用useHistory 调用来使用react-router-dom...

      - 首先

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

      -其次 在你的函数内部......编写一个函数来处理按钮点击

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

      - 最后

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

      【讨论】:

      • 在第 6 版中,useHistory 不适用您可以使用 useNavigate 代替
      • 是的,useNavigate 是新引入的。
      【解决方案15】:

      当我搜索答案时,每个人都在谈论 react-router-dom 的旧版本,所以对于那些想要在功能组件中使用钩子的人来说,这可能是一个有用的答案。与新版本一样,更改了一些钩子,甚至 withRouter 也不适用,您需要制作自定义 HOC。

      我们可以通过功能组件来实现,你可以使用你的按钮,然后通过useNavigate钩子描述onClick事件触发到下一页。

      React-Router-Dom 版本 6


      这只能在功能组件中使用,因为我正在使用钩子,如果你想在类组件上使用,那么你可以制作 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'}}>
      
      
      </>
      
      )
      
      
      
      }
      

      要使用类组件访问 useNavigate(),您必须转换为函数组件,或者滚动您自己的自定义 withRouter 高阶组件以注入“路由道具”,如来自 react-router-dom v5 的 withRouter HOC .x 做到了。


      这只是一个大概的想法。 如果你想使用导航这里是自定义withRouter HOC 的示例:

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

      并用新的 HOC 装饰组件。

      export default withRouter(Post);
      

      这将为类组件注入props

      【讨论】:

        猜你喜欢
        • 2019-04-13
        • 2020-11-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-11-25
        • 1970-01-01
        • 1970-01-01
        • 2019-01-09
        相关资源
        最近更新 更多