7

How to get script inside dangerouslySetInnerHTML get executed?

class Page extends Component {

  render() {
    return (
      <script
        dangerouslySetInnerHTML={{ __html: `
          console.log('hello world');
          window.dataLayer = window.dataLayer || [];
          window.dataLayer.push({
            event: 'viewCart'
          });
        ` }}
      />
    );
  }
}

I can't get console.log('hello world') executed. Anybody can help? Thank you

1

2 Answers 2

9

Script elements don't get executed because of the way that react-dom creates them.

When ReactDOM.createElement receives a type of 'script' it uses .innerHTML instead of using document.createElement like you might expect.

var div = document.createElement('div');
div.innerHTML = '<script></script>';

var element = div.removeChild(div.firstChild);

Creating the script in this way sets the "parser-inserted" flag on that element to true. This flag tells the browser that it should not execute.


https://github.com/facebook/react/blob/c2a2d8a539bf02e40c43d36adc2826e228f30955/packages/react-dom/src/client/ReactDOMComponent.js#L406

https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML#Security_considerations

https://www.w3.org/TR/2008/WD-html5-20080610/dom.html#innerhtml0

Sign up to request clarification or add additional context in comments.

Comments

6

You can't because script tags are removed automatically for security.

The best way to work with javascript is to get the string separately and execute (or eval) it from componentWillMount or componentDidMount

class Page extends Component {

  componentDidMount() {
    const jsCode = `
      console.log('hello world');
      window.dataLayer = window.dataLayer || [];
      window.dataLayer.push({
        event: 'viewCart'
      })
    `;
    new Function(jsCode)();
  }

  // you can do something else here
  render() {
    return (
      <noscript />
    );
  }
}

You can obviously use any string. I presume you might be loading it from the server.

In the example above I used new Function()() which is very similar to eval() but works faster.

I used componentDidMount so i'm certain the script executes after the view is shown. Another difference between Will and Did mount is that Will mount executes on both server and client sides of universal (isomorphic) apps, whereas Did mount will only execute on the client side of universal apps.

5 Comments

It's Will mount that is executed on both, not Did mount
@MichaelRasoahaingo thanks for catching this. Fixed.
Would love a reference link to the react docs where the script tag is removed. I see that the script is written, but seems to be completely ignored.
It's not the React issue, it's how innerHTML should works This is because script tags injected via innerHTML are not executed for security reasons: developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML
@pherris see answer below

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.