Aggiunta di tag script a React / JSX

Ho un problema relativamente semplice di provare ad aggiungere script inline a un componente React. Quello che ho finora:

'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 (  

People

); } };

Ho anche provato:

  try{Typekit.load({ async: true });}catch(e){} 

Nessuno dei due approcci sembra eseguire lo script desiderato. Immagino sia una cosa semplice che mi manca. Qualcuno può dare una mano?

PS: Ignora il foobar, ho un vero e proprio id in uso che non mi sentivo di condividere.

Vuoi recuperare ed eseguire lo script più e più volte, ogni volta che viene eseguito il rendering di questo componente, o solo una volta quando questo componente viene montato nel DOM?

Forse provare qualcosa di simile a questo:

  componentDidMount () { const script = document.createElement("script"); script.src = "https://use.typekit.net/foobar.js"; script.async = true; document.body.appendChild(script); } 

Tuttavia, questo è veramente utile solo se lo script che vuoi caricare non è disponibile come modulo / pacchetto. In primo luogo, vorrei sempre:

  • Cerca il pacchetto su npm
  • Scarica e installa il pacchetto nel mio progetto ( npm install typekit )
  • import il pacchetto dove è necessario ( import Typekit from 'typekit'; )

Questo è probabilmente il modo in cui hai installato i pacchetti react e react-document-title dal tuo esempio, e c’è un pacchetto Typekit disponibile su npm .

Oltre alle risposte sopra puoi farlo:

 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 
(this.instance = el)} />; } }

Il div è vincolato a this e lo script viene iniettato in esso.

La demo può essere trovata su codesandbox.io

La risposta fornita da Alex Mcmillan mi ha aiutato di più, ma non ha funzionato per un tag script più complesso.

Ho modificato leggermente la sua risposta per trovare una soluzione per un tag lungo con varie funzioni che aveva già impostato “src”.

(Per il mio caso d’uso, la sceneggiatura aveva bisogno di vivere in testa che si riflette anche qui):

  componentWillMount () { const script = document.createElement("script"); const scriptText = document.createTextNode("complex script with functions ie everything that would go inside the script tags"); script.appendChild(scriptText); document.head.appendChild(script); } 

Ho creato un componente React per questo caso specifico: https://github.com/coreyleelarson/react-typekit

È sufficiente passare l’ID del kit del tipo Kit come supporto e sei a posto.

 import React from 'react'; import Typekit from 'react-typekit'; const HtmlLayout = () => (   

My Example React Component

); export default HtmlLayout;

Se è necessario avere il blocco in SSR (rendering lato server), un approccio con componentDidMount non funzionerà.

È ansible utilizzare invece la libreria retriggers. Il codice in React sarà:

 import Safe from "react-safe" // in render  { `try{Typekit.load({ async: true });}catch(e){}` }  

Il mio modo preferito è usare React Helmet: è un componente che consente una facile manipolazione della testina del documento in un modo in cui probabilmente sei già abituato.

per esempio

 import React from "react"; import {Helmet} from "react-helmet"; class Application extends React.Component { render () { return ( 
...
); } };

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

C’è una soluzione molto buona che utilizza Range.createContextualFragment .

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

Questo funziona per HTML arbitrario e conserva anche informazioni di contesto come document.currentScript .

È ansible utilizzare npm postscribe per caricare lo script nel componente di risposta

 postscribe('#mydiv', '') 

La soluzione dipende dallo scenario. Come nel mio caso, ho dovuto caricare un embedding del calendario all’interno di un componente di reazione.

Calendly cerca un div e legge dal suo attributo data-url e carica un iframe all’interno del suddetto div.

Va tutto bene quando si carica la pagina per la prima volta: prima viene eseguito il rendering con data-url . Quindi lo script del calendario viene aggiunto al corpo. Il browser lo scarica e lo valuta e torniamo tutti a casa felici.

Il problema arriva quando ti allontani e poi ritorni nella pagina. Questa volta lo script è ancora nel corpo e il browser non lo scarica nuovamente e lo rivaluta.

Difficoltà:

  1. Su componentWillUnmount trova e rimuovi l’elemento script. Quindi, per rimontare, ripetere i passaggi precedenti.
  2. Immettere $.getScript . Si tratta di un ingegnoso helper jquery che accetta un URI di script e un callback di successo. Una volta caricato lo script, lo valuta e triggers la richiamata di successo. Tutto quello che devo fare è nel mio componentDidMount $.getScript(url) . Il mio metodo di render ha già il div di calendario. E funziona liscio.

Ho trovato utili questi documenti: utilizzo di variabili globali

Spiega cosa succede quando lavoriamo con reactjs e manipolare index.html. Nel caso portato qui, la soluzione sarebbe quella di fare questo in codice di reazione

 const global_var = window.global_var; 

dove global_var è stato definito in uno script incluso in index.html