【问题标题】:react-router redirect to a different domain urlreact-router 重定向到不同的域 url
【发布时间】:2015-09-14 17:46:19
【问题描述】:

我正在使用 react-router 进行客户端路由。我有一个按钮,当有人单击该按钮时,我想将用户重定向到不同的 url。 例如,我想将用户重定向到“http://www.google.com”。我使用了导航混合并使用了 this.transitionTo("https://www.google.com")。但是当我这样做时,我得到了这个错误 不变违规:找不到名为“https://www.google.com”的路由。

我可以使用 window.location 但这是正确的方法吗?

【问题讨论】:

    标签: reactjs client-side react-router


    【解决方案1】:

    外部链接不需要react-router,可以使用常规链接元素(即<a href="..."/>)就可以了。

    只有当您有内部导航(即从组件到组件)时,您才需要react-router,浏览器的 URL 栏应该让您的应用看起来像是在实际切换“真实” URL。

    编辑,因为人们似乎认为如果你需要“先做工作”,你就不能使用<a href="...",一个这样做的例子:

    render() {
      return <a href={settings.externalLocation} onClick={evt => this.leave(evt)}/>
    }
    
    async leave(evt) {
      if (this.state.finalized) return;
    
      evt.preventDefault();
    
      // Do whatever you need to do, but do it quickly, meaning that if you need to do
      // various things, do them all in parallel instead of running them one by one:
      await Promise.all([
        utils.doAllTheMetrics(),
        user.logOutUser(),
        store.cleanUp(),
        somelib.whatever(),
      ]);
    
      // done, let's leave.
      this.setState({ finalized: true }), () => evt.target.click());
    }
    

    就是这样:当你点击链接时(你把它设置成一个按钮,因为这就是 CSS 的用途)React 会检查它是否可以安全地离开,作为状态检查。

    • 如果可以,它会让这种情况发生。
    • 如果不能:
      1. 它可以防止通过preventDefault() 发生导航,
      2. 做它需要做的任何工作,然后
      3. 将自己标记为“现在可以安全离开”,然后重新触发链接。

    【讨论】:

    • 这是一个怎样的答案?问题是“如何在单击按钮时将我的应用重定向到外部 url?”。问题概括为“如何以编程方式重定向以响应事件?”您不能为此使用链接元素...
    • A &lt;button&gt; 只是另一个内联 HTML 元素,例如 spanimga,唯一使它成为按钮的是 CSS。因此,您需要一个a,它设计 用于链接,并使用 CSS 样式使其看起来像您的按钮。因为这是在语义上设计您的页面/应用程序:您有一个链接,所以您将其设为链接,然后根据您的需要对其进行样式设置。与其倒退,不如从一个按钮开始,然后尝试强制它成为一个链接。当然,所有这些都是次要的,仍然坚定正确地建议您不需要 react-router 用于出站链接,因为错误信号。
    • 抱歉 - 我仍然没有正确传达挑战。这不是关于“使可点击的可见元素重定向出去”。它是关于在事件处理程序代码中处理事件后重定向出去的。可能是按钮 onClick 或其他事件激活了代码。在代码中,您需要根据一些编程逻辑将用户重定向到外部 url。问题是“window.location 是这样做的正确方法吗?”
    • 答案是“不,你使用的是常规链接元素”。如果您对此有自己的问题,并且比原来发布的问题更详细,请随时发布您自己的问题来引用这个问题。
    【解决方案2】:

    正如 cmets 对此答案所指出的那样,解决此问题的默认方法是使用带有 href 属性的锚元素(a 标记),该属性指向您要路由的目标 URL用户到。具有按钮外观但行为或锚点的按钮几乎是一种 Web 反模式。在这个答案中查看更多信息:https://stackoverflow.com/a/1667512/1460905

    也就是说,当网络应用程序需要执行某些操作然后才重定向用户时,肯定存在一种潜在的情况。在这种情况下,如果用户采取的主要操作是提交一些数据或真正执行操作,而重定向更多的是副作用,那么原始问题是有效的。

    在这种情况下,为什么不使用window 对象的location 属性呢?它甚至提供了一个很好的功能方法来访问外部位置。请参阅ref

    所以,如果你有一个组件,说

    class Button extends Component {
      render() {
        return (
          <button onClick={this.handleClick.bind(this)} />
        );
      }
    }
    

    然后添加 handleClick 使组件看起来像

    class Button extends Component {
      handleClick() {
        // do something meaningful, Promises, if/else, whatever, and then
        window.location.assign('http://github.com');
      }
    
      render() {
        return (
          <button onClick={this.handleClick.bind(this)} />
        );
      }
    }
    

    无需导入window,因为它是全球性的。应该可以在任何现代浏览器中完美运行。

    另外,如果你有一个声明为函数的组件,你可能会在状态改变时使用the effect hook 来改变位置,比如

    const Button = () => {
      const [clicked, setClicked] = useState(false);
    
      useEffect(() => {
        if (clicked) {
          // do something meaningful, Promises, if/else, whatever, and then
          window.location.assign('http://github.com');
        }
      });
    
      return (
        <button onClick={() => setClicked(true)}></button>
      );
    };
    

    【讨论】:

    • 顺便说一句,确保确实有必要这样做。当其他程序员有一天开始与您一起工作时,或者在您离开项目很久之后使用您的代码库时,这可能会给他们带来很多痛苦。
    • useEffect 钩子的好用例 :)
    • -1,即使在某些情况下“它会起作用”,但这违背了 Web 的所有前提!在这里查看更多解释:stackoverflow.com/a/1667512/1460905
    • 更新了答案。由于该问题没有指定响应按钮单击而发生的重定向是主要操作还是副作用,假设它是主要操作,a 应该优先于 button。 ?
    • 或者您仍然使用链接,因为您可以阻止导航发生,完成工作,然后自动重新触发链接。我已经在我的答案中添加了示例代码,因为即使在那种情况下:不要使用&lt;button&gt;
    【解决方案3】:

    我找不到使用 React Router 的简单方法。正如@Mike 所写,您应该在将用户发送到外部站点时使用锚点(&lt;a&gt; 标签)。

    我创建了一个自定义 &lt;Link&gt; 组件来动态决定是渲染 React-Router &lt;Link&gt; 还是常规 &lt;a&gt; 标签。

    import * as React from "react";
    import {Link, LinkProps} from "react-router-dom";
    
    const ReloadableLink = (props: LinkProps & { forceReload?: boolean }) => {
        const {forceReload, ...linkProps} = props;
        if (forceReload)
            return <a {...linkProps} href={String(props.to)}/>;
        else
            return <Link {...linkProps}>
                {props.children}
            </Link>
    };
    
    export default ReloadableLink;
    

    【讨论】:

      【解决方案4】:

      正如@Mike 'Pomax' Kamermans 所指出的,您可以只使用导航到外部链接。

      我通常这样做,is-internal-link

      import React from 'react'
      
      import { Link as ReactRouterLink} from 'react-router-dom'
      import { isInternalLink } from 'is-internal-link'
      
      const Link = ({ children, to, activeClassName, ...other }) => {
        if (isInternalLink(to)) {
          return (
            <ReactRouterLink to={to} activeClassName={activeClassName} {...other}>
              {children}
            </ReactRouterLink>
          )
        }
        return (
          <a href={to} target="_blank" {...other}>
            {children}
          </a>
        )
      }
      
      export default Link
      

      免责声明:我是这个is-internal-link的作者

      【讨论】:

        【解决方案5】:

        我遇到了同样的问题,我对该问题的研究发现我可以简单地使用“a href”标签。如果使用 target="_blank" 你应该写你的链接...

        <a href="https://yourLink.com" target="_blank" rel="noopener noreferrer">Your Link</a>
        

        【讨论】:

          【解决方案6】:

          您可以尝试创建一个链接元素并从代码中单击它。这对我有用

          const navigateUrl = (url) => {
          
          let element = document.createElement('a');
          
          if(url.startsWith('http://') || url.startsWith('https://')){
            element.href =  url;
          } else{
            element.href = 'http://' + url;
          }
          
          element.click();
          }
          

          【讨论】:

            猜你喜欢
            • 2018-09-03
            • 2019-08-07
            • 2023-02-19
            • 2018-07-04
            • 2017-09-01
            • 2017-11-30
            • 1970-01-01
            • 1970-01-01
            • 2019-12-29
            相关资源
            最近更新 更多