【问题标题】:How to run a React.js effect when a 3rd party library is loaded using useEffect?使用 useEffect 加载第 3 方库时如何运行 React.js 效果?
【发布时间】:2019-11-10 18:16:50
【问题描述】:

我正在尝试创建一个安装 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 的引用,以便在定义后执行效果?

【问题讨论】:

  • 您是否检查过setDrift(window.drift) 行是否已执行(使用断点或console.log('was here')
  • 它似乎像您期望的那样工作。 codepen.io/anon/pen/vqprox?editors=0011 只要你打电话给setDrift(window.drift),那么第二个效果肯定会运行。
  • @Aprillion 我做到了;我更新了源代码并将日志包含在我原来的问题中
  • 当我将setDrift(window.drift) 更改为setDrift(true) 时,依赖效果开始触发。为什么漂移设置为函数时不触发?
  • 我看不出useEffect(..., [drift]) 在第二次渲染期间没有执行的任何原因 - 你确定你的代码中没有useMemo 并且没有像{!window.drift &amp;&amp; &lt;Drift /&gt;} 这样的条件渲染吗?

标签: reactjs react-hooks use-effect


【解决方案1】:

您可以将 Drift 客户端作为脚本添加到 head 标签中。

工作示例


要使其正常工作,请将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 文件中,供 webpack 使用。

【讨论】:

    【解决方案2】:

    如果可以导入库,那就更好了:

    import Drift from 'drift'
    

    如果没有,我建议在index.js 中运行与 React 无关的命令式代码:

    import ReactDOM from 'react-dom'
    ...
    !function() {
      var t = window.driftt = window.drift = window.driftt || [];
      ...
    ReactDOM.render(...)
    

    或者从index.html(如果使用create-react-app,则在public文件夹中)中的单独文件执行脚本:

    <body>
      <div id='root'>
      <script src="drift.js"></script>
    </body>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-02
      • 2021-08-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-06
      • 1970-01-01
      • 2015-03-01
      相关资源
      最近更新 更多