我有一个相对简单的问题,试图将内联脚本添加到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实际上在使用,我不想分享。


当前回答

解决方案视场景而定。就像在我的情况下,我必须加载一个日历嵌入在一个react组件。

Calendly查找一个div并从它的data-url属性读取,并在该div中加载iframe。

第一次加载页面时一切正常:首先,呈现带有data-url的div。然后日历脚本添加到主体。浏览器下载并评估它,我们都高兴地回家了。

问题来了,当你导航离开,然后回到页面。这一次脚本仍然在主体中,浏览器不会重新下载和重新评估它。

Fix:

在componentWillUnmount上找到并删除脚本元素。然后重新安装,重复上述步骤。 进入.getScript美元。它是一个漂亮的jquery助手,接受一个脚本URI和一个成功回调。一旦加载了脚本,它就计算它并触发你的success回调。我所要做的是在我的componentDidMount $. getscript (url)。我的渲染方法已经有日历div。它工作顺利。

其他回答

只需在HTML文件中添加主体

<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin></script>

解决方案视场景而定。就像在我的情况下,我必须加载一个日历嵌入在一个react组件。

Calendly查找一个div并从它的data-url属性读取,并在该div中加载iframe。

第一次加载页面时一切正常:首先,呈现带有data-url的div。然后日历脚本添加到主体。浏览器下载并评估它,我们都高兴地回家了。

问题来了,当你导航离开,然后回到页面。这一次脚本仍然在主体中,浏览器不会重新下载和重新评估它。

Fix:

在componentWillUnmount上找到并删除脚本元素。然后重新安装,重复上述步骤。 进入.getScript美元。它是一个漂亮的jquery助手,接受一个脚本URI和一个成功回调。一旦加载了脚本,它就计算它并触发你的success回调。我所要做的是在我的componentDidMount $. getscript (url)。我的渲染方法已经有日历div。它工作顺利。

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

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上找到

这个答案解释了这种行为背后的原因。

任何渲染脚本标签的方法都不能像预期的那样工作:

为外部脚本使用script标记 使用dangerouslySetInnerHTML

Why

React DOM (web上的React渲染器)使用createElement调用将JSX渲染为DOM元素。

createElement使用innerHTML DOM API最终将这些添加到DOM(参见React源代码中的代码)。innerHTML不执行作为安全考虑而添加的脚本标记。这就是为什么React中的渲染脚本标签不能按预期工作的原因。

关于如何在React中使用脚本标签,请查看本页的其他答案。

对于多个脚本,使用这个

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