我试图在一个gatsby.js应用程序中添加两个脚本到特定页面。
页面是/apply
,第二个脚本依赖于第一个脚本(第一个脚本必须在第二个脚本之前加载)。
当然,这在传统站点上很简单,因为脚本将按顺序同步加载。但是在react-头盔中,脚本是异步加载的,所以我的第二个脚本错误(它试图在第一个脚本加载之前调用第一个函数)。
我从https://usehooks.com/useScript/上取了一个钩子,正试图让事情正常工作。
如果我在加载后检查页面源,两个脚本都存在,但我仍然在控制台中得到错误(好像script2试图在script1之前运行)。
myPage.js
const Apply = () => {
const scriptLoaded = useScript("https://myscripturl/script1.js");
if(scriptLoaded !== "ready"){
return <>Not loaded</>
}
return (
<>
<Helmet>
{scriptLoaded === "ready" &&
<script src="https://myscripturl/script2.js"></script>
}
</Helmet>
<!-- The rest of the page -->
</>
)
}
useScript.js
// taken from https://usehooks.com/useScript/
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
);
如果我将两个脚本放在/public
中的index.html中,代码将正常工作。但它当然会在应用中的每条路线上运行,这并不好。我想做的事有可能吗?
谢谢你的帮助。
您可以使用盖茨比的脚本API: https://www.gatsbyjs.com/docs/reference/built-in-components/gatsby-script/
它还有一个关于独立加载脚本的章节:https://www.gatsbyjs.com/docs/reference/built-in-components/gatsby-script/#loading-scripts-dependently
所以你的代码可以是:import React, { useState } from "react"
import { Script } from "gatsby"
function Apply() {
const [loaded, setLoaded] = useState(false)
return (
<>
<Script src="https://myscripturl/script1.js" onLoad={() => setLoaded(true)} />
{loaded && <Script src="https://myscripturl/script2.js" />}
</>
)
}
export default Apply