score:0

i couldn't find a simple way to do that with react router. as @mike wrote you should use anchor (<a> tags) when sending the user to external site.

i created a custom <link> component to dynamically decide whether to render a react-router <link> or regular <a> tag.

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;

score:1

as pointed by @mike 'pomax' kamermans, you can just use to navigate to external link.

i usually do it this way, with 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

disclaimer: i am the author of this is-internal-link

score:1

i had the same issue and my research into the issue uncovered that i could simply use an "a href" tag. if using target="_blank" you should write your link this...

<a href="https://yourlink.com" target="_blank" rel="noopener noreferrer">your link</a>

score:1

you can try and create a link element and click it from code. this work for me

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

score:6

you don't need react-router for external links, you can use regular link elements (i.e. <a href="..."/>) just fine.

you only need react-router when you have internal navigation (i.e. from component to component) for which the browser's url bar should make it look like your app is actually switching "real" urls.

edit because people seem to think you can't use an <a href="..." if you need to "do work first", an example of doing exactly that:

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

and that's it: when you click the link (that you styled to look like a button because that's what css is for) react checks if it can safely navigate away as a state check.

  • if it can, it lets that happen.
  • if it can't:
    1. it prevents the navigation of occurring via preventdefault(),
    2. does whatever work it needs to do, and then
    3. marks itself as "it is safe to leave now", then retriggers the link.

score:27

as pointed out in the comments to this answer, default way of solving this would be to use anchor element (the a tag) with href attribute that points at the destination url that you'd like to route the user to. a button that has appearance of a button but behavior or an anchor is pretty much a web anti-pattern. see more info in this answer: https://stackoverflow.com/a/1667512/1460905.

that said, there certainly is a potential scenario when a web app needs to perform some action and only then redirect the user. in this case, if primary action the user takes is submitting some data or really performing an action, and redirect is more of a side-effect, then the original question is valid.

in this case, why not use location property of window object? it even provides a nice functional method to go to external location. see the ref.

so, if you have a component, say

class button extends component {
  render() {
    return (
      <button onclick={this.handleclick.bind(this)} />
    );
  }
}

then add handleclick that would make the component look like

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

no need to import window since it's global. should work perfectly in any modern browser.

also, if you have a component that is declared as a function, you may possibly use the effect hook to change location when state changes, like

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

Related Query

More Query from same tag