#reactjs #use-effect #marketo
#reactjs #использование-эффект #marketo
Вопрос:
Я пытался загрузить форму Marketo на свой сайт Gatsby, и я нашел несколько полезных советов о том, как это сделать в 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 amp;amp; !formIsLoaded) {
const windowGlobal = typeof window !== 'undefined' amp;amp; window
windowGlobal.MktoForms2.loadForm(baseUrl, munchkinId, formId).whenRendered(setFormIsLoaded(true))
return
}
appendScript(baseUrl, setScriptLoaded)
}, [formIsLoaded, scriptLoaded, baseUrl, munchkinId, formId])
}
Проблема в том, что если я уйду со страницы и быстро вернусь, форма загрузится несколько раз.
Форма Marketo появляется много раз
Я не уверен, как очистить его в функции useEffect. Проблема в том, что loadForm
функция еще не вернулась, и когда я ухожу со страницы, а затем возвращаюсь, она фактически получает это возвращение, а затем отправляет другой запрос.
Кажется, я не могу найти решение для этого, используя состояние или функцию очистки. AbortController() казался действительно многообещающим, но я тоже не смог найти решение. Похоже, это должно быть легко исправить. Я не первый человек с этой проблемой, поскольку она появлялась здесь раньше, а также на форумах Marketo, но мне еще предстоит найти адекватное решение.
Заранее спасибо за любые советы!
Комментарии:
1. Не могли бы вы использовать оператор возврата useEffect для его очистки?
2. идеально ли загружать скрипт только один раз за сеанс?
Ответ №1:
MkToForms2
Поддерживает обратный вызов 4-го параметра, который вызывается с формой после 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
возврат обещанием (не требуется), вы можете очистить часть кода и удалить некоторые дополнительные зависимости от 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" amp;amp; 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 по умолчанию, чтобы скрыть все добавленные формы и вместо удаления форм, если они отменены, показывать их, если они не отменены:
if (!cancelled) {
$form.show();
}
Это не loadForm
помешает выполнению при перемещении вперед и назад, но должно гарантировать, что только текущему loadForm
разрешено отображать и сохранять форму на странице.
Ответ №2:
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])
}