Как запустить эффект React.js при загрузке сторонней библиотеки с помощью useEffect?
Я пытаюсь создать <Drift>
компонент, который монтирует сервис чата Drift:
Drift.js
import React, { useEffect, useState } from 'react'
export default function Drift (props) {
const [drift, setDrift] = useState(undefined)
// Evaluate the drift script once
useEffect(() => {
const script = document.getElementById('drift-script').innerHTML
window.eval(script)
}, [])
// Poll for drift availability
useEffect(() => {
const poller = setInterval(() => {
if (window.drift) {
setDrift(window.drift)
clearInterval(poller)
console.log('setDrift(fn) called')
}
}, 500)
return () => clearInterval(poller)
}, [])
// Configure the drift widget once
useEffect(() => {
console.log('drift depended effect triggered:')
console.log(typeof drift)
if (drift) {
console.log('drift is defined')
drift.config({
messages: {
welcomeMessage: 'Your code is being generated!'
}
})
drift.on('ready', function (api) {
console.log('drift ready')
api.widget.hide()
api.widget.show()
api.showWelcomeMessage()
})
}
else {
console.log('drift is undefined')
}
}, [drift])
return (
<div>
<script
id="drift-script"
dangerouslySetInnerHTML={{
__html: `
"use strict";
!function() {
var t = window.driftt = window.drift = window.driftt || [];
if (!t.init) {
if (t.invoked) return void (window.console && console.error && console.error("Drift snippet included twice."));
t.invoked = !0, t.methods = [ "identify", "config", "track", "reset", "debug", "show", "ping", "page", "hide", "off", "on" ],
t.factory = function(e) {
return function() {
var n = Array.prototype.slice.call(arguments);
return n.unshift(e), t.push(n), t;
};
}, t.methods.forEach(function(e) {
t[e] = t.factory(e);
}), t.load = function(t) {
var e = 3e5, n = Math.ceil(new Date() / e) * e, o = document.createElement("script");
o.type = "text/javascript", o.async = !0, o.crossorigin = "anonymous", o.src = "https://js.driftt.com/include/" + n + "/" + t + ".js";
var i = document.getElementsByTagName("script")[0];
i.parentNode.insertBefore(o, i);
};
}
}();
drift.SNIPPET_VERSION = '0.3.1';
drift.load('DRIFT_ID');
`
}}
/>
{ props.children }
</div>
)
}
Идея в том, что эффект запускается один раз window.drift
становится определенным. Однако эффект запускается только один раз - когда window.drift не определен.
Полный журнал:
drift depended effect triggered:
Drift.js:30 undefined
Drift.js:51 drift is undefined
Drift.js:20 setDrift(fn) called
Как я могу создать ссылку на window.drift, которая приводит к выполнению эффекта после его определения?
2 ответа
Если бы можно было импортировать библиотеку, это было бы предпочтительнее:
import Drift from 'drift'
Если нет, я бы предложил запустить императивный код, не связанный с React, в index.js
:
import ReactDOM from 'react-dom'
...
!function() {
var t = window.driftt = window.drift = window.driftt || [];
...
ReactDOM.render(...)
Или выполнить скрипт из отдельного файла в index.html
(в public
папка при использовании create-реагировать-приложение):
<body>
<div id='root'>
<script src="drift.js"></script>
</body>
Вы можете добавить клиент Drift в качестве скрипта в заголовок тега.
Рабочий пример
Чтобы это работало, добавьте содержимое скрипта, заданного параметром drift, в виде текста в файле. Затем загрузите это как скрипт в useEffect
путем создания тега сценария.
useEffect(() => {
const script = document.createElement("script");
script.setAttribute("type", "text/javascript");
script.innerHTML = drift;
document.head.appendChild(script);
return () => script.parentNode.removeChild(script);
}, []);
Кроме того, если вы хотите, чтобы это было доступно в вашем приложении, вы можете просто добавить его в качестве встроенного тега сценария в HTML-файл индекса шаблона, который используется веб-пакетом.