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


当前回答

你可以在以下链接找到最佳答案:

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'); 脚本。SRC = 'url';//加载的第三方库的URL。 脚本。id = 'libraryName';//例如,googleMaps或stripe document.body.appendChild(脚本); 脚本。Onload = () => { If (callback) callback(); }; } if (existingScript && callback) callback(); };

其他回答

你必须为这个脚本创建一个组件,你调用这个组件作为一个标准的ES6脚本标记

'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>
                </article>
            </DocumentTitle>
        );

        class Component extend Index.App {  
             <script src="https://use.typekit.net/foobar.js" />
             <script dangerouslySetInnerHTML={{__html: 'try{Typekit.load({ async: true });}catch(e){}'}}/>
        }
    }
};

你可以试着使用下面的语句:

确保你相信剧本

 <script>{`
            function myFunction(index, row) {
                return index;
            }
        `}
</script>

我试图编辑@Alex McMillan接受的答案,但它不让我,所以这里有一个单独的答案,你可以得到你加载的库的值。这是人们要求的非常重要的区别,也是我用stripe.js实现时需要的区别。

useScript.js

import { useState, useEffect } from 'react'

export const useScript = (url, name) => {

  const [lib, setLib] = useState({})

  useEffect(() => {
    const script = document.createElement('script')

    script.src = url
    script.async = true
    script.onload = () => setLib({ [name]: window[name] })

    document.body.appendChild(script)

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

  return lib

}

用法是这样的

const PaymentCard = (props) => {
  const { Stripe } = useScript('https://js.stripe.com/v2/', 'Stripe')
}

注意:将库保存在一个对象中,因为通常情况下库是一个函数,React会在存储状态时执行函数来检查更改——这将破坏库(如Stripe),期望用特定的参数调用——所以我们将其存储在一个对象中,以隐藏React并保护库函数不被调用。

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


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

与其他答案非常相似,只是使用默认值来清理未定义的检查

import { useEffect } from 'react'

const useScript = (url, selector = 'body', async = true) => {
  useEffect(() => {
    const element = document.querySelector(selector)
    const script = document.createElement('script')
    script.src = url
    script.async = async
    element.appendChild(script)
    return () => {
      element.removeChild(script)
    }
  }, [url])
}

export default useScript

使用

useScript('/path/to/local/script.js') // async on body
useScript('https://path/to/remote/script.js', 'html') // async on html 
useScript('/path/to/local/script.js', 'html', false) // not async on html.. e.g. this will block