4

I'm writing a React.js application where I want to use Link component from react-router package in order to conditionally redirect a user to another page. If some condition doesn't hold I set the to prop to empty string which works and doesn't cause page reload and the page stays in the exact same place it was. But I'm wondering if this is the best practice?

This is my solution:

import { Link } from 'react-router';

<Link to={condition === true ? '/some/other/url' : ''}>
    <div>
        my content
    </div>
</Link>

I don't see anything in the documentation regarding empty string input.

hitchhiker
  • 1,099
  • 5
  • 19
  • 44

5 Answers5

9

I've never linked something to nothing in HTML or React. That said, it seems you have few options:

Option 1 Conditionally render the div not the to attribute. If codition is true show Link with div if not show div with no Link. This is probably the more "common" way to do this. If your div is not as simple as 'My Content' I would move it into a functional Component. And use that component instead of <div>MyContent</div> shown below.

import { Link } from 'react-router';

{ condition ? 
   (
     <Link to='/some/other/url'>
      <div>My Content</div>
     </Link>
   ) : ( <div>My Content</div> )
} 

Option 2 Do what you did but use the # instead of an empty string.

import { Link } from 'react-router';

<Link to={condition === true ? '/some/other/url' : '#'}>
    <div>
        my content
    </div>
</Link>

Option 3 Disable the link if the condition is false.

import { Link } from 'react-router';

//a better name might be in order here
const handleLinkDisable = (e) => {
  const { condition }  = this.state; //just assuming it comes from state
  if(condition){ e.preventDefault(); }
}; 

<Link to='/some/other/url' onClick={handleLinkDisable}>
  <div>My Content</div>
</Link> 

Hope that helps.

Bens Steves
  • 2,633
  • 3
  • 17
  • 28
  • I like your option 3, it works without causing a page refresh. There're a few issues with your code: 1) `condition ? null : e.preventDefault();` is neither an assignment nor a call, js will not compile. I used `if (condition) {e.preventDefault()}`. 2) storing className in state would cause a rerender each time the button is clicked. 3) css disabling link color should be placed on Link element. Please update (at least change the line which will not compile) the answer and I will accept it – hitchhiker Aug 30 '19 at 18:42
1

to is a required prop for Link. If the url is empty better to hide the whole component:

   {
      condition && (
        <Link to={"/some/other/url"}>
          <div>my content</div>
        </Link>
      );
    }

If for some weird reason you need to have empty url, you can pass a space:

<Link to={condition === true ? '/some/other/url' : ' '}> // Whitespace here
    <div>
        my content
    </div>
</Link>
Clarity
  • 10,730
  • 2
  • 25
  • 35
  • but if the condition is false then I need to copy the content and show it anyway which is code duplication especially if there's a lot of code inside the `div` – hitchhiker Aug 21 '19 at 07:15
  • having whitespace works as well but do you have any reference which supports that it's a valid value for `to`? – hitchhiker Aug 21 '19 at 07:18
  • 2
    `Link` uses `a` html element, so anything which is valid `href` should be also supported by `Link`. – Clarity Aug 21 '19 at 07:21
  • 1
    Also if you look at the prop type of Link's `to` in the source code: `to: PropTypes.oneOfType([PropTypes.string, PropTypes.object]).isRequired` – Clarity Aug 21 '19 at 07:22
  • But according to this answer, https://stackoverflow.com/a/7676563/5863693 `href=""` reloads the page which doesn't happen in my environment. According to this answer https://stackoverflow.com/a/43340108/5863693 "an empty URI reference within a document is interpreted as a reference to the start of that document" which again doesn't happen in my environment. – hitchhiker Aug 21 '19 at 07:25
  • 1
    Link uses React routing, not the browser's one. That's why when you click on Link your page doesn't get reloaded, which is the case with normal `a` tag. – Clarity Aug 21 '19 at 07:34
  • ok but why do you suggest to have whitespace and just empty string? – hitchhiker Aug 21 '19 at 08:03
  • 1
    You'd get a warning if you use empty link: https://github.com/facebook/create-react-app/issues/4141 – Clarity Aug 21 '19 at 08:07
  • The solution stopped working for me. No changes were made to the code but now when I click at the `div` when the condition is false the page is refreshed. The component is wrapped in `withRouter` so React routing should be available. – hitchhiker Aug 21 '19 at 08:28
1

I just took a look at the latest documentation and I think I understand what is going on with an empty string for the to prop of a Link component. Since that is the question here, I will try to explain.

According to the docs, if the to value doesn't start with a slash (/) then it is considered a relative link and the following is the expected behavior:

A relative value (that does not begin with /) resolves relative to the parent route, which means that it builds upon the URL path that was matched by the route that rendered that .

Unfortunately this doesn't mean that an empty string will just link to the URL you are already on. If you had a route like this:

<Route path="/questions/:id" element={<MyElement />} />

and a URL like:

https://stackoverflow.com/questions/57586239/is-empty-string-valid-value-for-react-link

the 'match' part is just https://stackoverflow.com/questions/57586239, and this is what the Link with empty to will link you to. In fact you will see it as the href of the <a> element.

Even if your matched route exactly equals the current URL, so it seems like empty string trick might work, each Link click will create an entry in the navigation history which will mess up navigating backwards and forwards if the intention is for the link to be a no-op.

This last point means that even using a trick like <Link to={window.location.href}> won't work because it will still pollute the navigation history.

There are plenty of good alternative suggestions as answers to this question that will work, but I wanted to try to answer why empty string as to is a bad idea.

dbudzins
  • 436
  • 5
  • 8
0

Use <BUTTON> instead, you will have same pseudo like :active, :focus as link and it will get rid of warnings.

generally install: eslint; sonarlint extenstion... they will give you recommendation and industry standards for small errros like this.

fruitloaf
  • 1,628
  • 15
  • 10
-2

Use "javascript.void(0)" instead of using an empty string.

import {Link} from 'react-router';

mycontent

Kindly refer to docs What does "javascript:void(0)" mean?

  • This will trigger `Script URL is a form of eval no-script-url` lint error. – Clarity Aug 21 '19 at 08:10
  • void simply returns undefined, which means to do nothing. – Saumya Agrawal Aug 21 '19 at 08:18
  • you will get something like `Warning: A future version of React will block javascript: URLs as a security precaution. Use event handlers instead if you can. If you need to generate unsafe HTML try using dangerouslySetInnerHTML instead. React was passed "javascript:void(0)".` – irzhy Feb 23 '21 at 06:00