Javascript 将脚本标签添加到 React/JSX

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34424845/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 16:18:59  来源:igfitidea点击:

Adding script tag to React/JSX

javascriptreactjsecmascript-6react-jsx

提问by ArrayKnight

I have a relatively straightforward issue of trying to add inline scripting to a React component. What I have so far:

我有一个相对简单的问题,即尝试向 React 组件添加内联脚本。到目前为止我所拥有的:

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

I have also tried:

我也试过:

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

Neither approach seems to execute the desired script. I'm guessing it's a simple thing I'm missing. Can anybody help out?

这两种方法似乎都没有执行所需的脚本。我猜这是我错过的一件简单的事情。有人可以帮忙吗?

PS: Ignore the foobar, I have a real id actually in use that I didn't feel like sharing.

PS:忽略 foobar,我有一个真正在使用的真实 id,我不想分享。

回答by Alex McMillan

Edit: Things change fast and this is outdated - see update

编辑:事情变化很快,这已经过时了 - 请参阅更新



Do you want to fetch and execute the script again and again, every time this component is rendered, or just once when this component is mounted into the DOM?

你想一次又一次地获取和执行脚本,每次渲染这个组件时,还是当这个组件被挂载到 DOM 时才一次?

Perhaps try something like this:

也许尝试这样的事情:

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

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

    document.body.appendChild(script);
}

However, this is only really helpful if the script you want to load isn't available as a module/package. First, I would always:

但是,这仅在您要加载的脚本不能作为模块/包使用时才真正有用。首先,我总是:

  • Look for the package on npm
  • Download and install the package in my project (npm install typekit)
  • importthe package where I need it (import Typekit from 'typekit';)
  • npm上查找包
  • 在我的项目中下载并安装包 ( npm install typekit)
  • import我需要的包裹 ( import Typekit from 'typekit';)

This is likely how you installed the packages reactand react-document-titlefrom your example, and there is a Typekit package available on npm.

这可能是你如何安装的软件包react,并react-document-title从你的榜样,并有一个在NPM提供Typekit包



Update:

更新:

Now that we have hooks, a better approach might be to use useEffectlike so:

现在我们有了钩子,更好的方法可能是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);
  }
}, []);

Which makes it a great candidate for a custom hook (eg: hooks/useScript.js):

这使它成为自定义钩子的绝佳候选者(例如:)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;

Which can be used like so:

可以这样使用:

import useScript from 'hooks/useScript';

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

  // rest of your component
}

回答by sidonaldson

Further to the answers above you can do this:

除了上面的答案,您还可以这样做:

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

The div is bound to thisand the script is injected into it.

div 被绑定,this脚本被注入其中。

Demo can be found on codesandbox.io

可以在codeandbox.io上找到演示

回答by AC Patrice

My favorite way is to use React Helmet – it's a component that allows for easy manipulation of the document head in a way you're probably already used to.

我最喜欢的方法是使用 React Helmet——它是一个组件,允许以您可能已经习惯的方式轻松操作文档头。

e.g.

例如

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

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

回答by scabbiaza

If you need to have <script>block in SSR (server-side rendering), an approach with componentDidMountwill not work.

如果您需要<script>在 SSR(服务器端渲染)中使用块,则使用 的方法componentDidMount将不起作用。

You can use react-safelibrary instead. The code in React will be:

您可以改用react-safe库。React 中的代码将是:

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>

回答by jake2620

The answer Alex Mcmillanprovided helped me the most but didn't quite work for a more complex script tag.

Alex Mcmillan提供的答案对我帮助最大,但对于更复杂的脚本标签却不太适用。

I slightly tweaked his answer to come up with a solution for a long tag with various functions that was additionally already setting "src".

我稍微调整了他的答案,为具有各种功能的长标签提出了一个解决方案,这些功能另外已经设置了“src”。

(For my use case the script needed to live in head which is reflected here as well):

(对于我的用例,脚本需要存在于头脑中,这也反映在此处):

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

回答by Corey Larson

I created a React component for this specific case: https://github.com/coreyleelarson/react-typekit

我为这个特定案例创建了一个 React 组件:https: //github.com/coreyleelarson/react-typekit

Just need to pass in your Typekit Kit ID as a prop and you're good to go.

只需将您的 Typekit Kit ID 作为道具传递,您就可以开始使用了。

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;

回答by Maximilian Hils

There is a very nice workaround using Range.createContextualFragment.

有一个非常好的解决方法,使用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));
}

This works for arbitrary HTML and also retains context information such as document.currentScript.

这适用于任意 HTML 并保留上下文信息,例如document.currentScript.

回答by Ashh

You can use npm postscribeto load script in react component

您可以使用npm postscribe在反应组件中加载脚本

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

回答by Muhammad Usama Rabani

You can also use react helmet

您也可以使用反应头盔

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

Helmet takes plain HTML tags and outputs plain HTML tags. It's dead simple, and React beginner friendly.

Helmet 采用纯 HTML 标签并输出纯 HTML 标签。它非常简单,而且 React 初学者友好。

回答by ben

for multiple scripts, use this

对于多个脚本,使用这个

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