web-dev-qa-db-fra.com

Ajout d'une balise de script à React / JSX

J'ai un problème relativement simple d'essayer d'ajouter un script inline à un composant React. Ce que j'ai jusqu'ici:

'use strict';

import '../../styles/pages/people.scss';

import React, { Component } from 'react';
import DocumentTitle from 'react-document-title';

import { prefix } from '../../core/util';

export default class extends Component {
    render() {
        return (
            <DocumentTitle title="People">
                <article className={[prefix('people'), prefix('people', 'index')].join(' ')}>
                    <h1 className="tk-brandon-grotesque">People</h1>

                    <script src="https://use.typekit.net/foobar.js"></script>
                    <script dangerouslySetInnerHTML={{__html: 'try{Typekit.load({ async: true });}catch(e){}'}}></script>
                </article>
            </DocumentTitle>
        );
    }
};

J'ai aussi essayé:

<script src="https://use.typekit.net/foobar.js"></script>
<script>try{Typekit.load({ async: true });}catch(e){}</script>

Aucune approche ne semble exécuter le script souhaité. Je suppose que c'est une chose simple qui me manque. Quelqu'un peut-il aider?

PS: Ignorez la foobar, j'ai un identifiant réellement utilisé que je n'avais pas envie de partager.

180
ArrayKnight

Voulez-vous extraire et exécuter le script encore et encore, chaque fois que ce composant est rendu, ou juste une fois lorsque ce composant est monté dans le DOM?

Peut-être essayer quelque chose comme ça:

componentDidMount () {
    const script = document.createElement("script");

    script.src = "https://use.typekit.net/foobar.js";
    script.async = true;

    document.body.appendChild(script);
}

Cependant, cela n’est vraiment utile que si le script que vous voulez charger n’est pas disponible en tant que module/package. D'abord, je voudrais toujours:

  • Recherchez le package sur npm
  • Téléchargez et installez le package dans mon projet (npm install typekit)
  • import le paquet où j'en ai besoin (import Typekit from 'typekit';)

C'est probablement ainsi que vous avez installé les packages react et react-document-title à partir de votre exemple. Il existe un package Typekit disponible sur npm .

254
Alex McMillan

En plus des réponses ci-dessus, vous pouvez le faire:

import React from 'react';

export default class Test extends React.Component {
  constructor(props) {
    super(props);
  }

  componentDidMount() {
    const s = document.createElement('script');
    s.type = 'text/javascript';
    s.async = true;
    s.innerHTML = "document.write('This is output by document.write()!')";
    this.instance.appendChild(s);
  }

  render() {
    return <div ref={el => (this.instance = el)} />;
  }
}

Le div est lié à this et le script y est injecté.

La démo peut être trouvée sur codesandbox.io

42
sidonaldson

Ma méthode préférée consiste à utiliser React Helmet - il s'agit d'un composant qui permet de manipuler facilement la tête du document d'une manière à laquelle vous êtes probablement déjà habitué.

par exemple.

import React from "react";
import {Helmet} from "react-helmet";

class Application extends React.Component {
  render () {
    return (
        <div className="application">
            <Helmet>
                <script src="https://use.typekit.net/foobar.js"></script>
                <script>try{Typekit.load({ async: true });}catch(e){}</script>
            </Helmet>
            ...
        </div>
    );
  }
};

https://github.com/nfl/react-helmet

32
Patrice Wrex

La réponse Alex Mcmillan fournie m'aide le plus, mais ne fonctionne pas tout à fait pour une balise de script plus complexe.

J'ai légèrement modifié sa réponse pour trouver une solution pour une longue balise avec diverses fonctions qui mettait déjà déjà "src".

(Pour mon cas d'utilisation, le script avait besoin de vivre en tête, ce qui est reflété ici aussi):

  componentWillMount () {
      const script = document.createElement("script");

      const scriptText = document.createTextNode("complex script with functions i.e. everything that would go inside the script tags");

      script.appendChild(scriptText);
      document.head.appendChild(script);
  }
11
jake2620

Si vous devez avoir un bloc _<script>_ en SSR (rendu côté serveur), une approche avec componentDidMount ne fonctionnera pas.

Vous pouvez utiliser la bibliothèque react-safe à la place. Le code dans React sera:

_import Safe from "react-safe"

// in render 
<Safe.script src="https://use.typekit.net/foobar.js"></Safe.script>
<Safe.script>{
  `try{Typekit.load({ async: true });}catch(e){}`
}
</Safe.script>
_
9
scabbiaza

J'ai créé un composant React _ pour ce cas particulier: https://github.com/coreyleelarson/react-typekit

Il vous suffit de passer votre ID de kit Typekit comme accessoire et vous êtes prêt à partir.

import React from 'react';
import Typekit from 'react-typekit';

const HtmlLayout = () => (
  <html>
    <body>
      <h1>My Example React Component</h1>
      <Typekit kitId="abc123" />
    </body>
  </html>
);

export default HtmlLayout;
7
Corey Larson

Il existe une solution très agréable utilisant Range.createContextualFragment.

/**
 * Like React's dangerouslySetInnerHTML, but also with JS evaluation.
 * Usage:
 *   <div ref={setDangerousHtml.bind(null, html)}/>
 */
function setDangerousHtml(html, el) {
    if(el === null) return;
    const range = document.createRange();
    range.selectNodeContents(el);
    range.deleteContents();
    el.appendChild(range.createContextualFragment(html));
}

Cela fonctionne pour du HTML arbitraire et conserve également des informations de contexte telles que document.currentScript.

3
Maximilian Hils

Vous pouvez utiliser npm postscribe pour charger le script dans le composant de réaction

_postscribe('#mydiv', '<script src="https://use.typekit.net/foobar.js"></script>')
_
2
Ashh
componentDidMount() {
  const head = document.querySelector("head");
  const script = document.createElement("script");
  script.setAttribute(
    "src",
    "https://assets.calendly.com/assets/external/widget.js"
  );
  head.appendChild(script);
}
0
Marlcg58

pour plusieurs scripts, utilisez cette

var loadScript = function(src) {
  var tag = document.createElement('script');
  tag.async = false;
  tag.src = src;
  document.getElementsByTagName('body').appendChild(tag);
}
loadScript('//cdnjs.com/some/library.js')
loadScript('//cdnjs.com/some/other/library.js')
0
ben

J'ai essayé toutes les solutions proposées mais aucune ne fonctionne. J'essaie d'intégrer cela à un composant mais il ne se charge pas. c'est une bannière de bannersnack.com .

<script type="text/javascript">
var bannersnack_embed = {"hash":"bxpien9pr","width":1190,"height":300,"t":1559889975,"userId":39254375,"responsive":true,"type":"html5"};
</script>
<script type="text/javascript" src="//cdn.bannersnack.com/iframe/embed.js"></script>
0
Charm

J'ai document "undefined" lors de l'actualisation. Alors j'ai essayé de cette façon

const MyComponent = () => {
   let script = React.createElement("script", {
    src: "https://.....js path",
    async: true,
    defer: true,
    crossorigin: "anonymous"
})

return (

        <div>
            {script}
        </div>)
}
0
Asanka