Agregar etiqueta de script a React/JSX

Resuelto ArrayKnight asked hace 8 años • 29 respuestas

Tengo un problema relativamente sencillo al intentar agregar secuencias de comandos en línea a un componente de React. Lo que tengo hasta ahora:

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

También he probado:

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

Ninguno de los enfoques parece ejecutar el script deseado. Supongo que es algo simple lo que me falta. ¿Alguien puede ayudar?

PD: ignora la barra de menú, tengo una identificación real en uso que no tenía ganas de compartir.

ArrayKnight avatar Dec 23 '15 04:12 ArrayKnight
Aceptado

Editar: las cosas cambian rápidamente y esto está desactualizado; ver actualización


¿Quiere recuperar y ejecutar el script una y otra vez, cada vez que se procesa este componente, o solo una vez cuando este componente se monta en el DOM?

Quizás intente algo como esto:

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

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

    document.body.appendChild(script);
}

Sin embargo, esto sólo es realmente útil si el script que desea cargar no está disponible como módulo/paquete. Primero, siempre haría:

  • Busque el paquete en npm
  • Descargar e instalar el paquete en mi proyecto ( npm install typekit)
  • importel paquete donde lo necesito ( import Typekit from 'typekit';)

Probablemente así es como instaló los paquetes reacty react-document-titlesegún su ejemplo, y hay un paquete Typekit disponible en npm .


Actualizar:

Ahora que tenemos ganchos, un mejor enfoque podría ser usarlos useEffectasí:

useEffect(() => {
  const script = document.createElement('script');

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

  document.body.appendChild(script);

  return () => {
    document.body.removeChild(script);
  }
}, []);

Lo que lo convierte en un gran candidato para un gancho personalizado (por ejemplo:) hooks/useScript.js:

import { useEffect } from 'react';

const useScript = url => {
  useEffect(() => {
    const script = document.createElement('script');

    script.src = url;
    script.async = true;

    document.body.appendChild(script);

    return () => {
      document.body.removeChild(script);
    }
  }, [url]);
};

export default useScript;

Que se puede utilizar así:

import useScript from 'hooks/useScript';

const MyComponent = props => {
  useScript('https://use.typekit.net/foobar.js');

  // rest of your component
}
Alex McMillan avatar Dec 22 '2015 21:12 Alex McMillan

Mi forma favorita es usar React Helmet: es un componente que permite una fácil manipulación del cabezal del documento de una manera a la que probablemente ya esté acostumbrado.

p.ej

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

cdcdcd avatar Dec 09 '2017 21:12 cdcdcd

Además de las respuestas anteriores, puede hacer esto:

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

El div está vinculado thisy el script se inyecta en él.

La demostración se puede encontrar en codesandbox.io

sidonaldson avatar Feb 08 '2017 12:02 sidonaldson

Esta respuesta explica el por qué detrás de este comportamiento.

Cualquier método para representar la scriptetiqueta no funciona como se esperaba:

  1. Usando la scriptetiqueta para scripts externos
  2. UsandodangerouslySetInnerHTML

Por qué

React DOM (el renderizador de reaccionar en la web) utiliza createElementllamadas para representar JSX en elementos DOM.

createElementutiliza la innerHTMLAPI DOM para finalmente agregarlos al DOM ( consulte el código en la fuente de React ). innerHTML no ejecutascript la etiqueta agregada como consideración de seguridad. Y esta es la razón por la que, a su vez, la representación de scriptetiquetas en React no funciona como se esperaba.

Para saber cómo usar scriptetiquetas en React, consulte otras respuestas en esta página.

Divyanshu Maithani avatar Nov 13 '2020 04:11 Divyanshu Maithani

Si necesita tener <script>un bloqueo en SSR (renderizado del lado del servidor), un enfoque componentDidMountno funcionará.

Puedes usar react-safela biblioteca en su lugar. El código en React será:

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>
scabbiaza avatar Jan 21 '2018 19:01 scabbiaza