प्रतिक्रिया / JSX के लिए स्क्रिप्ट टैग जोड़ना


264

मेरे पास एक प्रतिक्रियाशील घटक में इनलाइन स्क्रिप्टिंग जोड़ने की कोशिश करने का एक अपेक्षाकृत सीधा मुद्दा है। मेरे पास अब तक क्या है:

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

मैंने भी कोशिश की है:

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

न तो दृष्टिकोण वांछित स्क्रिप्ट को निष्पादित करने के लिए लगता है। मुझे लग रहा है कि यह एक साधारण बात है जो मुझे याद आ रही है। क्या कोई मदद कर सकता है?

पुनश्च: फोबोवर को नजरअंदाज करें, मेरे पास वास्तव में एक वास्तविक आईडी है जो कि मुझे साझा करने का मन नहीं करता था।


5
क्या आपके आधार पृष्ठ HTML में इसे शामिल करने के बजाय React के माध्यम से इसे लोड करने की कोई विशेष प्रेरणा है? यहां तक ​​कि अगर यह काम करता है, तो इसका मतलब है कि आप हर बार घटक को माउंट करने के लिए एक स्क्रिप्ट को फिर से सम्मिलित करेंगे।
loganfsmyth

क्या यह मामला है? मुझे लगता है कि डोम अलग करने से ऐसा नहीं होगा, लेकिन मैं मानता हूं कि यह लागू होने पर निर्भर करेगा DocumentTitle
लोगनफ़्समीथ

8
सही @loganfsmyth, प्रतिक्रिया फिर से रेंडर पर स्क्रिप्ट को फिर से लोड नहीं करेगा अगर अगले राज्य में भी स्क्रिप्ट है।
अधिकतम

जवाबों:


403

संपादित करें: चीजें तेजी से बदलती हैं और यह पुरानी है - अपडेट देखें


क्या आप स्क्रिप्ट को बार-बार लाने और निष्पादित करने के लिए चाहते हैं, हर बार इस घटक को प्रस्तुत किया जाता है, या बस एक बार जब यह घटक DOM में माउंट किया जाता है?

शायद कुछ इस तरह की कोशिश करें:

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

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

    document.body.appendChild(script);
}

हालाँकि, यह केवल वास्तव में मददगार होता है यदि आप जिस स्क्रिप्ट को लोड करना चाहते हैं वह मॉड्यूल / पैकेज के रूप में उपलब्ध नहीं है। सबसे पहले, मैं हमेशा रहूंगा:

  • Npm पर पैकेज के लिए देखें
  • मेरी परियोजना में पैकेज डाउनलोड और स्थापित करें ( npm install typekit)
  • importपैकेज जहां मुझे इसकी आवश्यकता है ( import Typekit from 'typekit';)

यह संभव है कि आपने अपने उदाहरण से पैकेजों को कैसे स्थापित किया reactऔर npm परreact-document-title एक टाइपकाट पैकेज उपलब्ध है


अपडेट करें:

अब जब हमारे पास हुक हैं, तो एक बेहतर तरीका उपयोग करने के लिए हो सकता है useEffect:

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);
  }
}, []);

जो इसे कस्टम हुक के लिए एक महान उम्मीदवार बनाता है (जैसे:) 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;

जिसका उपयोग इस तरह किया जा सकता है:

import useScript from 'hooks/useScript';

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

  // rest of your component
}

धन्यवाद। मैं इस गलत के बारे में सोच रहा था। मैं इसे लागू करने के साथ आगे बढ़ा। सिर्फ जोड़ने के try{Typekit.load({ async: true });}catch(e){}बादappendChild
ArrayKnight

2
मैंने तय किया कि टाइपकिट से "उन्नत" कार्यान्वयन इस दृष्टिकोण के लिए अधिक उपयुक्त था।
ArrayKnight

10
यह काम करता है - स्क्रिप्ट को लोड करने के लिए, लेकिन मैं स्क्रिप्ट में कोड तक कैसे पहुंच सकता हूं। उदाहरण के लिए, मैं एक फ़ंक्शन को कॉल करना चाहता हूं जो स्क्रिप्ट के अंदर रहता है, लेकिन मैं इसे उस घटक के अंदर नहीं भेज पा रहा हूं जहां स्क्रिप्ट लोड है।
जीरो_कोल ११'१६

2
जब स्क्रिप्ट को पृष्ठ में जोड़ दिया जाता है तो इसे सामान्य रूप से निष्पादित किया जाएगा। उदाहरण के लिए, यदि आपने सीडीएन से jQuery डाउनलोड करने के लिए इस विधि का उपयोग किया है, तो componentDidMountफ़ंक्शन डाउनलोड होने के बाद और स्क्रिप्ट को पृष्ठ पर जोड़ दिया, तो आपके पास jQueryऔर $ऑब्जेक्ट्स विश्व स्तर पर उपलब्ध होंगे (अर्थात: पर window)।
एलेक्स मैकमिलन

1
मुझे प्रमाणीकरण स्क्रिप्ट का उपयोग करने में एक समान समस्या थी और यह पता चला कि इसे रूट के html फ़ाइल में आपकी प्रतिक्रिया App.js. के ऊपर एक परत में शामिल करना बेहतर हो सकता है। मामले में किसी को भी यह उपयोगी लगता है। @Loganfsmith उल्लेख किया है ...
devssh

57

ऊपर दिए गए उत्तरों से आप यह कर सकते हैं:

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

Div को बाध्य किया गया है thisऔर स्क्रिप्ट को इसमें इंजेक्ट किया गया है।

डेमो codeandbox.io पर पाया जा सकता है


5
this.instance ने मेरे लिए काम नहीं किया, लेकिन दस्तावेज़।
क्या होगा कूल

6
आप शायद this.instanceअपने रेंडर विधि के अंदर रेफरी से नहीं बंधे । मैंने इसे प्रदर्शित करने के लिए एक डेमो लिंक जोड़ा है
जुडी

1
@ ShubhamKushwah आप सर्वर साइड रेंडरिंग कर रहे होंगे?
ArrayKnight

@ArrayKnight हाँ मुझे बाद में पता चला कि सर्वर पर ये ऑब्जेक्ट मौजूद नहीं हैं: document, window। इसलिए मैं npm globalपैकेज का उपयोग करना पसंद करता हूं
शुभम कुशवाह

s.async = true की क्या आवश्यकता है, मुझे इसके बारे में कोई संदर्भ नहीं मिला, यह जानने के लिए कि क्या यह उद्देश्य है, क्या आप इसे समझा सकते हैं
sasha romanov

50

मेरा पसंदीदा तरीका रिएक्ट हेलमेट का उपयोग करना है - यह एक घटक है जो दस्तावेज़ के सिर के आसान हेरफेर की अनुमति देता है जिस तरह से आप शायद पहले से ही इस्तेमाल कर रहे हैं।

जैसे

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


5
यह अब तक का सबसे अच्छा समाधान है।
पक्काश

4
दुर्भाग्य से, यह काम नहीं कर रहा है ... कोडसंदबॉक्स
s/

2
@Darkowic, मुझे आपके कोड async="true"को उस <script>टैग से जोड़कर काम करना था जिसने jQuery को कोड में जोड़ा था।
सोमा म्बादेवी

@SomaMbadiwe क्यों इसके साथ काम करता है async=trueऔर इसके बिना विफल रहता है?
वेबवॉमन

3
कोशिश की, यह मेरे लिए काम नहीं करता है। मैं एकमात्र कारण के लिए प्रतिक्रिया-हेलमेट का उपयोग करने की सलाह नहीं दूंगा कि यह स्क्रिप्ट में अतिरिक्त गुणों को इंजेक्ट करता है जिसे हटाया नहीं जा सकता। यह वास्तव में कुछ लिपियों को तोड़ता है, और अनुरक्षकों ने इसे वर्षों में तय नहीं किया है, और github.com/nfl/react-helmet/issues/79
Philberg

16

यदि आपको <script>SSR (सर्वर-साइड रेंडरिंग) में ब्लॉक करने की आवश्यकता है , तो एक दृष्टिकोण componentDidMountकाम नहीं करेगा।

आप react-safeइसके बजाय लाइब्रेरी का उपयोग कर सकते हैं । प्रतिक्रिया में कोड होगा:

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>

12

एलेक्स मैकमिलन ने जो उत्तर दिया, उसने मुझे सबसे अधिक मदद की लेकिन अधिक जटिल स्क्रिप्ट टैग के लिए काम नहीं किया।

मैंने थोड़े से टैग के साथ एक समाधान के साथ आने के लिए अपने जवाब को थोड़ा अलग किया, जो पहले से ही "src" सेट कर रहा था।

(मेरे उपयोग के मामले के लिए स्क्रिप्ट को सिर में रहने की ज़रूरत है जो यहाँ भी परिलक्षित है):

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

7
मुझे समझ नहीं आ रहा है कि अगर आप सिर्फ इनलाइन JS को पृष्ठ पर डंप कर रहे हैं तो आप React का उपयोग क्यों करेंगे ...?
एलेक्स मैकमिलन

2
आपको document.head.removeChild(script);अपने कोड में जोड़ने की आवश्यकता है , या जब तक उपयोगकर्ता इस पृष्ठ मार्ग पर नहीं जाता है, तब तक आप अपने html पर अनंत संख्या में स्क्रिप्ट टैग बनाएंगे
sasha romanov

7

मैंने इस विशिष्ट मामले के लिए एक प्रतिक्रिया घटक बनाया: https://github.com/coreyleelarson/react-typekit

बस आपको एक टाइप के रूप में अपने टाइपेकिट किट आईडी में पास होने की जरूरत है और आप जाने के लिए अच्छे हैं।

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;

3

का उपयोग करके एक बहुत अच्छा समाधान है 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));
}

यह मनमाने ढंग से HTML के लिए काम करता है और संदर्भ जानकारी को भी बनाए रखता है document.currentScript


क्या आप इस बात का सहयोग कर सकते हैं कि उपयोग नमूना के साथ कृपया इसे कैसे काम करने की उम्मीद है? मेरे लिए यह स्क्रिप्ट और उदाहरण के लिए बॉडी के साथ काम नहीं कर रहा है ..
एलेक्स एफिमोव

3

आप npm postscribeप्रतिक्रिया घटक में स्क्रिप्ट लोड करने के लिए उपयोग कर सकते हैं

postscribe('#mydiv', '<script src="https://use.typekit.net/foobar.js"></script>')

1
मेरी समस्या का समाधान करता है
आरपीचियोली

1

आप प्रतिक्रिया हेलमेट का भी उपयोग कर सकते हैं

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

class Application extends React.Component {
  render () {
    return (
        <div className="application">
            <Helmet>
                <meta charSet="utf-8" />
                <title>My Title</title>
                <link rel="canonical" href="http://example.com/example" />
                <script src="/path/to/resource.js" type="text/javascript" />
            </Helmet>
            ...
        </div>
    );
  }
};

हेलमेट सादे HTML टैग लेता है और सादे HTML टैग आउटपुट करता है। यह मृत सरल है, और रिएक्टर शुरुआती अनुकूल है।


0

एकाधिक स्क्रिप्ट के लिए, इसका उपयोग करें

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

आप निम्न लिंक पर सर्वश्रेष्ठ उत्तर पा सकते हैं:

https://cleverbeagle.com/blog/articles/tutorial-how-to-load-third-party-scripts-dynamically-in-javascript

const loadDynamicScript = (callback) => {
const existingScript = document.getElementById('scriptId');

if (!existingScript) {
    const script = document.createElement('script');
    script.src = 'url'; // URL for the third-party library being loaded.
    script.id = 'libraryName'; // e.g., googleMaps or stripe
    document.body.appendChild(script);

    script.onload = () => {
      if (callback) callback();
    };
  }

  if (existingScript && callback) callback();
};

0

एलेक्स मैकमिलन के समाधान के अनुसार , मेरे पास निम्नलिखित अनुकूलन है।
मेरा अपना वातावरण: प्रतिक्रिया 16.8+, अगले v9 +

// स्क्रिप्ट
/ हुक / Script.js नामक एक कस्टम घटक जोड़ें

import { useEffect } from 'react'

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

    script.src = url
    script.async = (typeof async === 'undefined' ? true : async )

    document.body.appendChild(script)

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

export default function Script({ src, async=true}) {

  useScript(src, async)

  return null  // Return null is necessary for the moment.
}

// कस्टम कम्पोनेट का उपयोग करें, बस इसे आयात करें और पुराने कम केस <script>टैग को विकल्प दें, कस्टम कैमल केस <Script>टैग पर्याप्त होगा।
// index.js

import Script from "../hooks/Script";

<Fragment>
  {/* Google Map */}
  <div ref={el => this.el = el} className="gmap"></div>

  {/* Old html script */}
  {/*<script type="text/javascript" src="http://maps.google.com/maps/api/js"></script>*/}

  {/* new custom Script component */}
  <Script src='http://maps.google.com/maps/api/js' async={false} />
</Fragment>

इस घटक के लिए एक चेतावनी है: यह स्क्रिप्ट घटक केवल अपने भाई-बहनों के आदेश की गारंटी दे सकता है। यदि आप एक ही पृष्ठ के कई घटकों में कई बार इस घटक का उपयोग करते हैं, तो स्क्रिप्ट ब्लॉक क्रम से बाहर हो सकते हैं। कारण यह है कि सभी लिपियों को डाक्यूमेंट्री के बजाय document.body.appendChild द्वारा प्रोग्रामेटिक रूप से डाला जाता है। खैर हेलमेट हेड टैग में सभी स्क्रिप्ट टैग को स्थानांतरित करता है, जो हम नहीं चाहते हैं।
sully

अरे @ सच में, मेरी समस्या यह है कि स्क्रिप्ट को गंभीर रूप से DOM में जोड़ा जा रहा है, सबसे अच्छा समाधान जो मैंने अब तक देखा है वह है कॉम्पोनेंट अनमाउंटिंग के दौरान, DOM से चाइल्ड एलिमेंट (यानी <script>) को हटाना, और फिर यह किया जा रहा है फिर से जोड़ा जब घटक डोम पर मुहिम शुरू की है (मैं प्रतिक्रिया-राउटर-डोम का उपयोग कर रहा हूं और मेरे सभी घटकों के केवल एक घटक को इस स्क्रिप्ट की आवश्यकता है)
Eazy

0

पार्टी में थोड़ी देर हो गई लेकिन मैंने @ एलेक्स मैकमिलन के जवाबों को देखने के बाद अपना खुद का निर्माण करने का फैसला किया और दो अतिरिक्त मापदंडों को पार करके; वह स्थिति जिसमें लिपियों को रखना या रखना या सत्य को असत्य पर स्थापित करना यहाँ है:

import { useEffect } from 'react';

const useScript = (url, position, async) => {
  useEffect(() => {
    const placement = document.querySelector(position);
    const script = document.createElement('script');

    script.src = url;
    script.async = typeof async === 'undefined' ? true : async;

    placement.appendChild(script);

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

export default useScript;

इसे कॉल करने का तरीका ठीक वैसा ही है जैसा कि इस पोस्ट के स्वीकृत उत्तर में दिखाया गया है लेकिन दो अतिरिक्त (फिर से) मापदंडों के साथ:

// First string is your URL
// Second string can be head or body
// Third parameter is true or false.
useScript("string", "string", bool);

0

प्रतिक्रिया परियोजना में JS फ़ाइलों को आयात करने के लिए इस कमिंग का उपयोग करें

  1. JS फ़ाइल को प्रोजेक्ट पर ले जाएँ।
  2. निम्नलिखित कमांड का उपयोग करके पेज में js आयात करें

यह सरल और आसान है।

import  '../assets/js/jquery.min';
import  '../assets/js/popper.min';
import  '../assets/js/bootstrap.min';

मेरे मामले में, मैं अपनी प्रतिक्रिया परियोजना में इन जेएस फाइलों को आयात करना चाहूंगा।


-3

समाधान परिदृश्य पर निर्भर करता है। मेरे मामले की तरह, मुझे एक प्रतिक्रिया घटक के अंदर एक कैलेंडर को एम्बेड करना था।

कैलेंडली एक डिव की तलाश करता है और उसकी data-urlविशेषता को पढ़ता है और उक्त डिव के अंदर एक आइफ्रेम लोड करता है।

जब आप पहली बार पेज लोड करते हैं तो यह सब अच्छा होता है: पहला, डिव के साथ data-urlप्रदान किया जाता है। फिर कैलेंडली स्क्रिप्ट को शरीर में जोड़ा जाता है। ब्राउज़र डाउनलोड करता है और इसका मूल्यांकन करता है और हम सभी घर खुश होते हैं।

समस्या तब आती है जब आप दूर जाते हैं और फिर पृष्ठ में वापस आते हैं। इस बार स्क्रिप्ट अभी भी शरीर में है और ब्राउज़र इसे फिर से डाउनलोड और पुनर्मूल्यांकन नहीं करता है।

ठीक कर:

  1. componentWillUnmountस्क्रिप्ट तत्व को खोजने और निकालने पर। फिर पुनः माउंट पर, उपरोक्त चरणों को दोहराएं।
  2. दर्ज करें $.getScript। यह एक निफ्टी jquery हेल्पर है जो एक स्क्रिप्ट URI और एक सफलता कॉलबैक लेता है। एक बार यह स्क्रिप्ट लोड होने के बाद, यह इसका मूल्यांकन करती है और आपकी सफलता को वापस लेती है। मुझे बस इतना करना है कि मेरे अंदर क्या है componentDidMount $.getScript(url)। मेरी renderविधि पहले से ही कैलेंडली div है। और यह सुचारू रूप से काम करता है।

2
ऐसा करने के लिए jQuery जोड़ना एक बुरा विचार है, साथ ही आपका मामला आपके लिए बहुत विशिष्ट है। वास्तव में एक बार कैलेंडली स्क्रिप्ट को जोड़ने के साथ कुछ भी गलत नहीं है क्योंकि मुझे यकीन है कि एपीआई में फिर से पता लगाने वाली कॉल है। बार-बार स्क्रिप्ट जोड़ना और जोड़ना सही नहीं है।
साइडलॉन्सर

@sidonaldson jQuery एक बुरा अभ्यास नहीं है यदि आप एक परियोजना को अलग-अलग फ्रेमवर्क के आर्किटेक्चर कंपाउंड को बनाए रखेंगे (और libs) न केवल प्रतिक्रिया करें, इसके अलावा हमें घटकों तक पहुंचने के लिए देशी js का उपयोग करने की आवश्यकता है
AlexNikonov
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.