Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React 16.9.0 "javascript:;" href alternative? [duplicate]

After updating to React 16.9.0 I'm getting big warnings like this:

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:;".

It comes from code like this:

const Component = ({someAction}) => (
  <a href="javascript:void(0)" onClick={someAction}>click me</a>
);

Looking at the StackOverflow question about which “href” value should I use for JavaScript links in HTML it seems most of you agree javascript:void(0) is the best option, which will be no longer possible in React 16.9.0.

Just replacing with href="#" is problematic, since the browser will scroll to the top of the page and change the displayed URL. Especially if you use hash-links for routing this is very problematic.

I could update my whole codebase to have e.preventDefault(); in each and every event handler, but this seems hard to do, especially when the event handlers are automatically created from Redux action creators or hooks. I do not look for the answer "just include e.preventDefault();" everywhere!

Also using a <button> means I have to deal with lots of unwanted styles applied.

So I was wondering: Are there any solutions specific to the library React to get a working <a> link that just triggers an action without side effects? I want to change the code as little as possible and get rid of deprecation warnings.

like image 230
amoebe Avatar asked Aug 15 '19 17:08

amoebe


People also ask

What can I use instead of JavaScript void 0?

Another alternative to JavaScript void 0 is to use return false. When the click returns false, the browser will not take any action.

What is HREF in React JS?

Refs are a function provided by React to access the DOM element and the React element that you might have created on your own. They are used in cases where we want to change the value of a child component, without making use of props and all.

How do you do nothing in React?

To cause anchors to do nothing on click in React, we can call e. preventDefault in the click handler function of the anchor.


2 Answers

In React blog post:

URLs starting with javascript: are a dangerous attack surface because it’s easy to accidentally include unsanitized output in a tag like <a href> and create a security hole.

In React 16.9, this pattern continues to work, but it will log a warning. If you use javascript: URLs for logic, try to use React event handlers instead.

I personally prefer to use it like this: <a href="#!" onClick={clickAction}>Link</a>

like image 184
N'Bayramberdiyev Avatar answered Sep 17 '22 16:09

N'Bayramberdiyev


I came up with a component like this:

import React, {useCallback} from 'react';

function AHrefJavascript({ children, onClick, ...props }) {
  const handleClick = useCallback(
    e => {
      e.preventDefault();
      return onClick(e);
    },
    [onClick]
  );

  return (
    <a href="#javascript" {...props} onClick={handleClick}>
      {children}
    </a>
  );
}

It will just wrap the event handler to create a new one that also calls e.preventDefault(). It will add a hash link to href which does not trigger the deprecation warning. Using the power of hooks it only changes the event handler, when the passed in handler is updated. One problem with this that in the browser you can still open this link in a new tab, so it is not quite as good as a link with a javascript:void(0), which would prevent that.

It is easy to use, the component looks like this:

const Component = ({someAction}) => (
  <AHrefJavascript onClick={someAction}>click me</a>
);

So probably one could replace a href="javascript:void(0)" with AHrefJavascript across the project and then just add an import for the component everywhere.

In the end maybe the best option is to use a <button> and go through the hoops to remove all the unwanted styles.

like image 25
amoebe Avatar answered Sep 17 '22 16:09

amoebe