我有一个相对简单的问题,试图将内联脚本添加到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。它工作顺利。
要在head tag <head>中添加脚本标签或代码,请使用react-helmet包。它很轻,有很好的文档。
在script标签中添加Js代码
function htmlDecode(html) {
return html.replace(/&([a-z]+);/ig, (match, entity) => {
const entities = { amp: '&', apos: '\'', gt: '>', lt: '<', nbsp: '\xa0', quot: '"' };
entity = entity.toLowerCase();
if (entities.hasOwnProperty(entity)) {
return entities[entity];
}
return match;
});
}
render() {
const scriptCode = `<script type="text/javascript">
{(function() {
window.hello={
FIRST_NAME: 'firstName',
LAST_NAME: 'lastName',
};
})()}
</script>`
return(
<div dangerouslySetInnerHTML={{ __html: this.htmlDecode(scriptCode) }} />;
);
}
这段代码可以通过console.log(windows.hello)进行测试。
根据Alex McMillan的解决方案,我有如下的调整。
我自己的环境:React 16.8+,下一个v9+
//添加一个名为Script的自定义组件
/ / / Script.js hook
import { useEffect } from 'react'
// react-helmet don't guarantee the scripts execution order
export default function Script(props) {
// Ruels: alwasy use effect at the top level and from React Functions
useEffect(() => {
const script = document.createElement('script')
// src, async, onload
Object.assign(script, props)
let { parent='body' } = props
let parentNode = document.querySelector(parent)
parentNode.appendChild(script)
return () => {
parentNode.removeChild(script)
}
} )
return null // Return null is necessary for the moment.
}
//使用自定义组件,只需导入它,并将旧的小写<script>标记替换为自定义驼色大小写<script>标记就足够了。
/ / index.js
import Script from "../hooks/Script";
<Fragment>
{/* Google Map */}
<div ref={el => this.el = el} className="gmap"></div>
{/* Old html script */}
{/*<script type="text/javascript" src="http://maps.google.com/maps/api/js"></script>*/}
{/* new custom Script component */}
<Script async={false} type="text/javascript" src='http://maps.google.com/maps/api/js' />
</Fragment>
以下是我如何最终能够在React JS代码中添加两个外部JavaScript文件:
以下是我遵循的步骤。
步骤1:
我在react-app文件夹路径中使用npm I React-Helmet从终端安装了React-Helmet。
步骤2:
然后我添加了import {Helmet} from "react-helmet";头在我的代码。
步骤3:
最后,在我的代码中这是
我如何使用Helment添加外部JS文件
<Helmet>
<script src = "path/to/my/js/file1.js" type = "text/javascript" />
<script src = "path/to/my/js/file2.js" type = "text/javascript" />
</Helmet>
要获得支持加载状态和错误处理的更完整的useScript实现,请查看useHooks。
使用
function App() {
const status = useScript(
"https://pm28k14qlj.codesandbox.io/test-external-script.js"
);
return (
<div>
<div>
Script status: <b>{status}</b>
</div>
{status === "ready" && (
<div>
Script function call response: <b>{TEST_SCRIPT.start()}</b>
</div>
)}
</div>
);
}
Hook
function useScript(src) {
// Keep track of script status ("idle", "loading", "ready", "error")
const [status, setStatus] = useState(src ? "loading" : "idle");
useEffect(
() => {
// Allow falsy src value if waiting on other data needed for
// constructing the script URL passed to this hook.
if (!src) {
setStatus("idle");
return;
}
// Fetch existing script element by src
// It may have been added by another intance of this hook
let script = document.querySelector(`script[src="${src}"]`);
if (!script) {
// Create script
script = document.createElement("script");
script.src = src;
script.async = true;
script.setAttribute("data-status", "loading");
// Add script to document body
document.body.appendChild(script);
// Store status in attribute on script
// This can be read by other instances of this hook
const setAttributeFromEvent = (event) => {
script.setAttribute(
"data-status",
event.type === "load" ? "ready" : "error"
);
};
script.addEventListener("load", setAttributeFromEvent);
script.addEventListener("error", setAttributeFromEvent);
} else {
// Grab existing script status from attribute and set to state.
setStatus(script.getAttribute("data-status"));
}
// Script event handler to update status in state
// Note: Even if the script already exists we still need to add
// event handlers to update the state for *this* hook instance.
const setStateFromEvent = (event) => {
setStatus(event.type === "load" ? "ready" : "error");
};
// Add event listeners
script.addEventListener("load", setStateFromEvent);
script.addEventListener("error", setStateFromEvent);
// Remove event listeners on cleanup
return () => {
if (script) {
script.removeEventListener("load", setStateFromEvent);
script.removeEventListener("error", setStateFromEvent);
}
};
},
[src] // Only re-run effect if script src changes
);
return status;
}