Как запустить эффект React.js при загрузке сторонней библиотеки с помощью useEffect? - PullRequest
1 голос
/ 28 июня 2019

Я пытаюсь создать компонент <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 ]

1 голос
/ 29 июня 2019

Если бы можно было импортировать библиотеку, это было бы предпочтительнее:

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>
1 голос
/ 29 июня 2019

Вы можете добавить клиент Drift в качестве сценария в тег head.

Рабочий пример

Edit kind-shape-1wus8


Чтобы все заработало, добавьте содержимое скрипта, заданного параметром 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);
}, []);

Также, если вы хотите, чтобы это было доступно в вашем приложении, вы можете просто добавить его как встроенныйтег script в HTML-файле индекса шаблона, который используется веб-пакетом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...