我有一个相对简单的问题,试图将内联脚本添加到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>
        );
    }
};

我也试过:

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

这两种方法似乎都不能执行所需的脚本。我猜我错过了一件简单的事。有人能帮忙吗?

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


当前回答

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

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被绑定到此,脚本被注入其中。

演示可以在codesandbox.io上找到

其他回答

你可以在react被调用之前把你的脚本放在Html文件中。

编辑:事情变化很快,这是过时的-见更新


您是希望在每次呈现该组件时,还是在将该组件挂载到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 Typekit from ' Typekit ';)

这可能就是你安装例子中的react和react-document-title包的方式,npm上有一个Typekit包可用。


更新:

现在我们有了钩子,一个更好的方法可能是像这样使用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
}

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

您可以使用反应安全库代替。 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>

对于多个脚本,使用这个

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