首页 > 解决方案 > React 中带有类的外部脚本

问题描述

我正在尝试将外部地图服务嵌入到我的 React 应用程序中。他们建议将 API 集成到常规 HTML 网页中,如下所示:

<script type="text/javascript" src="//map.search.ch/api/map.js"></script>
<script type="text/javascript">new SearchChMap({center:[123456,987654],y:"-1m",poigroups:"default"});</script>

我尝试在我的typescriptReact 组件中应用它,如下所示:

declare class SearchChMap {
  constructor(_: {})
}

// ...

<>
  <script type="text/javascript" src="//map.search.ch/api/map.js"></script>
  <script type="text/javascript">{new SearchChMap({ center: [123456, 987654], poigroups: "default" })}</script>
  {/* ... */}
</>

编译时,我收到以下运行时错误:ReferenceError: SearchChMap is not defined.

在 React 组件中使用来自外部托管脚本的遗留 JavaScript 类的正确方法是什么?

更新:

我尝试了这个答案无济于事,使用以下代码:

componentDidMount(): void {
  const script1: HTMLScriptElement = document.createElement("script");
  script1.src = "//map.search.ch/api/map.js";
  script1.async = true;
  document.body.appendChild(script1);

  const script2: HTMLScriptElement = document.createElement("script");
  script2.text = 'new SearchChMap({center:[123456,987654],y:"-1m",poigroups:"default"});';
  script2.async = true;
  document.body.appendChild(script2);
}

这会在几秒钟后导致完全相同的错误消息,因为脚本是动态添加的。

更新 2:

将对象创建移动到onload建议AWolf的技巧:

componentDidMount(): void {
  const scriptTag: HTMLScriptElement = document.createElement("script");
  scriptTag.src = "//map.search.ch/api/map.js";
  document.head.appendChild(scriptTag);

  scriptTag.onload = () => {
    new SearchChMap({ center: this.props.center, container: this.props.containerId });
  };
}

标签: javascriptreactjstypescript

解决方案


您可以添加脚本标签public/index.html并将其与它一起使用,window.SearchChMap或者如果您更喜欢从您的代码中加载它,您componentDidMount可以像下面的代码片段一样进行操作(与以下沙箱中的代码相同)。

它使用onload附加的脚本标签来延迟对象的创建,直到新脚本被加载。

使用useRef了,因此您可以在函数的其他位置使用创建的对象(示例中未使用)。

代码中useEffect需要确保在添加标签之前 DOM 已准备好。componentDidMount与具有生命周期方法的基于类的组件中的行为相同。的返回useEffect可用于进行清理,例如return () => { /* remove script tag & dispose the window.SearchChMap */}(与 相同componentWillUnmount

import React, { useEffect, useRef } from "react";

export default () => {
  const SearchMap = useRef(); // optional, but useful if the Map object is used after mounting
  useEffect(() => {
    const scriptTag = document.createElement("script");
    scriptTag.src = "//map.search.ch/api/map.js";
    document.body.appendChild(scriptTag);

    scriptTag.onload = () => {
      SearchMap.current = new window.SearchChMap({ center: "Zürich" });
    };
  }, [SearchMap]);

  return (
    <div
      id="mapcontainer"
      style={{ maxWidth: "500px", height: "400px", border: "2px inset #ccc" }}
    />
  );
};

推荐阅读