如何阻止第三方 Javascript 加载清理功能?
How can you stop third party Javascript from loading in a cleanup function?
我一直在尝试在我的 Gatsby 网站上加载 Marketo 表单,并且我在 Stack Overflow 上找到了一些关于如何执行此操作的有用提示,但在所有示例中,都存在一个我无法解决的问题'好像解决不了。
组件如下:
import React from 'react'
import useMarketo from '../../hooks/useMarketo'
export default function MarketoForm({ formId }) {
const baseUrl = '//XXX-XXX.marketo.com'
const munchkinId = 'XXX-XXX-XXX'
useMarketo(baseUrl, munchkinId, formId)
return <form id={`mktoForm_${formId}`} />
}
这里是钩子:
import { useState, useEffect } from 'react'
function appendScript(baseUrl, setScriptLoaded) {
if (window.MktoForms2) return setScriptLoaded(true)
const script = document.createElement('script')
script.src = `${baseUrl}/js/forms2/js/forms2.min.js`
script.onload = () => (window.MktoForms2 ? setScriptLoaded(true) : null)
document.body.appendChild(script)
}
export default function useMarketo(baseUrl, munchkinId, formId) {
const [formIsLoaded, setFormIsLoaded] = useState(false)
const [scriptLoaded, setScriptLoaded] = useState(false)
useEffect(() => {
if (scriptLoaded && !formIsLoaded) {
const windowGlobal = typeof window !== 'undefined' && window
windowGlobal.MktoForms2.loadForm(baseUrl, munchkinId, formId).whenRendered(setFormIsLoaded(true))
return
}
appendScript(baseUrl, setScriptLoaded)
}, [formIsLoaded, scriptLoaded, baseUrl, munchkinId, formId])
}
问题是,如果我离开页面,并且 return 很快,表单将加载多次。
Marketo Form appears many times
我不确定如何在 useEffect 函数中清除它。问题是 loadForm
函数还没有 returned,当我离开页面然后返回时,它实际上得到 return,然后发送出去另一个请求。
我似乎找不到使用状态或清理功能解决此问题的方法。 AbortController() 看起来很有前途,但我也找不到解决方案。不过,这似乎应该很容易解决。我不是第一个遇到此问题的人,因为它以前曾出现在此处以及 Marketo 论坛上 - 但我尚未找到合适的解决方案。
提前感谢您的任何建议!
const scripts = {};
function importScript(url) {
if (!scripts[url]) {
const script = document.createElement('script');
scripts[url] = {
loaded: false,
fail: false,
resolves: [],
rejects: [],
}
script.onload = ()=> {
scripts[url].loaded = true;
scripts[url].resolves.forEach(r=> r());
}
script.onerror = (err)=> {
scripts[url].fail = true;
scripts[url].rejects.forEach(r=> r());
}
}
if (scripts[url].fail) return Promise.reject();
if (scripts[url].loaded) return Promise.resolve();
return new Promise((r, j)=> {
scripts[url].resolves.push(r);
scripts[url].rejects.push(j);
});
}
export default function useMarketo(baseUrl, munchkinId, formId) {
useEffect(() => {
importScript(baseUrl).then(()=> {
windowGlobal.MktoForms2.loadForm(baseUrl, munchkinId, formId);
}, console.error);
}, [formIsLoaded, scriptLoaded, baseUrl, munchkinId, formId])
}
MkToForms2
支持 4th parameter 回调,在 loadForm
完成后随表单一起调用。我的建议是使用效果清理功能来跟踪何时卸载 useMarketo
挂钩,如果卸载它则使用 loadForm
回调来删除表单。
windowGlobal.MktoForms2.loadForm(
baseUrl,
munchkinId,
formId,
(form) => {
const $form = form.getFormElem();
// if this was cancelled do not show it and remove it
if (cancelled) {
$form.remove();
return;
}
// if not cancelled this is still valid, lets show it and update form loading status
setFormIsLoaded(true);
}
);
此外,通过使 appendScript
return 成为一个承诺(不需要),您可以清理一些代码并删除一些您可能不需要的对 loadForm
效果的额外依赖需要。以下是我的推介。
function appendScript(baseUrl) {
return new Promise((resolve, reject) => {
const existingScript = document.body.getElementById(baseUrl);
if (existingScript) {
return resolve(true);
}
if (window.MktoForms2) {
resolve(true);
}
const script = document.createElement("script");
script.src = `${baseUrl}/js/forms2/js/forms2.min.js`;
script.onload = () => resolve(window.MktoForms2);
script.onerror = reject;
document.body.appendChild(script);
});
}
export default function useMarketo(baseUrl, munchkinId, formId) {
const [formIsLoaded, setFormIsLoaded] = useState(false);
useEffect(() => {
let cancelled = false;
const loadForm = async () => {
const scriptLoaded = await appendScript(baseUrl);
if (scriptLoaded) {
const windowGlobal = typeof window !== "undefined" && window;
windowGlobal.MktoForms2.loadForm(
baseUrl,
munchkinId,
formId,
(form) => {
const $form = form.getFormElem();
// if this was cancelled do not show it and remove it
if (cancelled) {
$form.remove();
return;
}
// if not cancelled this is still valid, lets show it and update form loading status
setFormIsLoaded(true);
}
);
}
};
loadForm();
return () => {
cancelled = true;
};
}, [baseUrl, munchkinId, formId]);
}
我不确定表格删除是否会显示添加表格然后删除表格的闪光,但如果确实如此,那么您应该添加默认值 css class 以隐藏所有添加的表格,如果取消则不删除表格,如果未取消则显示它们:
if (!cancelled) {
$form.show();
}
这不会阻止 loadForm
在来回导航时执行,但它应该确保只允许当前 loadForm
显示和保留页面上的表单。
我一直在尝试在我的 Gatsby 网站上加载 Marketo 表单,并且我在 Stack Overflow 上找到了一些关于如何执行此操作的有用提示,但在所有示例中,都存在一个我无法解决的问题'好像解决不了。
组件如下:
import React from 'react'
import useMarketo from '../../hooks/useMarketo'
export default function MarketoForm({ formId }) {
const baseUrl = '//XXX-XXX.marketo.com'
const munchkinId = 'XXX-XXX-XXX'
useMarketo(baseUrl, munchkinId, formId)
return <form id={`mktoForm_${formId}`} />
}
这里是钩子:
import { useState, useEffect } from 'react'
function appendScript(baseUrl, setScriptLoaded) {
if (window.MktoForms2) return setScriptLoaded(true)
const script = document.createElement('script')
script.src = `${baseUrl}/js/forms2/js/forms2.min.js`
script.onload = () => (window.MktoForms2 ? setScriptLoaded(true) : null)
document.body.appendChild(script)
}
export default function useMarketo(baseUrl, munchkinId, formId) {
const [formIsLoaded, setFormIsLoaded] = useState(false)
const [scriptLoaded, setScriptLoaded] = useState(false)
useEffect(() => {
if (scriptLoaded && !formIsLoaded) {
const windowGlobal = typeof window !== 'undefined' && window
windowGlobal.MktoForms2.loadForm(baseUrl, munchkinId, formId).whenRendered(setFormIsLoaded(true))
return
}
appendScript(baseUrl, setScriptLoaded)
}, [formIsLoaded, scriptLoaded, baseUrl, munchkinId, formId])
}
问题是,如果我离开页面,并且 return 很快,表单将加载多次。
Marketo Form appears many times
我不确定如何在 useEffect 函数中清除它。问题是 loadForm
函数还没有 returned,当我离开页面然后返回时,它实际上得到 return,然后发送出去另一个请求。
我似乎找不到使用状态或清理功能解决此问题的方法。 AbortController() 看起来很有前途,但我也找不到解决方案。不过,这似乎应该很容易解决。我不是第一个遇到此问题的人,因为它以前曾出现在此处以及 Marketo 论坛上 - 但我尚未找到合适的解决方案。
提前感谢您的任何建议!
const scripts = {};
function importScript(url) {
if (!scripts[url]) {
const script = document.createElement('script');
scripts[url] = {
loaded: false,
fail: false,
resolves: [],
rejects: [],
}
script.onload = ()=> {
scripts[url].loaded = true;
scripts[url].resolves.forEach(r=> r());
}
script.onerror = (err)=> {
scripts[url].fail = true;
scripts[url].rejects.forEach(r=> r());
}
}
if (scripts[url].fail) return Promise.reject();
if (scripts[url].loaded) return Promise.resolve();
return new Promise((r, j)=> {
scripts[url].resolves.push(r);
scripts[url].rejects.push(j);
});
}
export default function useMarketo(baseUrl, munchkinId, formId) {
useEffect(() => {
importScript(baseUrl).then(()=> {
windowGlobal.MktoForms2.loadForm(baseUrl, munchkinId, formId);
}, console.error);
}, [formIsLoaded, scriptLoaded, baseUrl, munchkinId, formId])
}
MkToForms2
支持 4th parameter 回调,在 loadForm
完成后随表单一起调用。我的建议是使用效果清理功能来跟踪何时卸载 useMarketo
挂钩,如果卸载它则使用 loadForm
回调来删除表单。
windowGlobal.MktoForms2.loadForm(
baseUrl,
munchkinId,
formId,
(form) => {
const $form = form.getFormElem();
// if this was cancelled do not show it and remove it
if (cancelled) {
$form.remove();
return;
}
// if not cancelled this is still valid, lets show it and update form loading status
setFormIsLoaded(true);
}
);
此外,通过使 appendScript
return 成为一个承诺(不需要),您可以清理一些代码并删除一些您可能不需要的对 loadForm
效果的额外依赖需要。以下是我的推介。
function appendScript(baseUrl) {
return new Promise((resolve, reject) => {
const existingScript = document.body.getElementById(baseUrl);
if (existingScript) {
return resolve(true);
}
if (window.MktoForms2) {
resolve(true);
}
const script = document.createElement("script");
script.src = `${baseUrl}/js/forms2/js/forms2.min.js`;
script.onload = () => resolve(window.MktoForms2);
script.onerror = reject;
document.body.appendChild(script);
});
}
export default function useMarketo(baseUrl, munchkinId, formId) {
const [formIsLoaded, setFormIsLoaded] = useState(false);
useEffect(() => {
let cancelled = false;
const loadForm = async () => {
const scriptLoaded = await appendScript(baseUrl);
if (scriptLoaded) {
const windowGlobal = typeof window !== "undefined" && window;
windowGlobal.MktoForms2.loadForm(
baseUrl,
munchkinId,
formId,
(form) => {
const $form = form.getFormElem();
// if this was cancelled do not show it and remove it
if (cancelled) {
$form.remove();
return;
}
// if not cancelled this is still valid, lets show it and update form loading status
setFormIsLoaded(true);
}
);
}
};
loadForm();
return () => {
cancelled = true;
};
}, [baseUrl, munchkinId, formId]);
}
我不确定表格删除是否会显示添加表格然后删除表格的闪光,但如果确实如此,那么您应该添加默认值 css class 以隐藏所有添加的表格,如果取消则不删除表格,如果未取消则显示它们:
if (!cancelled) {
$form.show();
}
这不会阻止 loadForm
在来回导航时执行,但它应该确保只允许当前 loadForm
显示和保留页面上的表单。