我有一个相对简单的问题,试图将内联脚本添加到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实际上在使用,我不想分享。
有点晚了,但我决定创建我自己的@Alex Macmillan的答案后,这是通过传递两个额外的参数;放置脚本的位置,如或和设置async为true/false,这里是:
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);
我试图编辑@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