I am trying to embed an external map service into my React app. Their recommendation to integrate the API into a regular HTML web page looks like this:
<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>
I tried to apply this in my typescript
React component as follows:
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>
{/* ... */}
</>
While this compiles, I receive the following runtime error: ReferenceError: SearchChMap is not defined
.
What is the correct way of using legacy JavaScript classes from an externally hosted script in your React components?
I tried this answer to no avail, using the following code:
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);
}
This results in the exact same error message, just a few seconds later, since the scripts are added dynamically.
Moving the object creation to onload
as suggested by AWolf
did the trick:
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 });
};
}
You could add the script tag to public/index.html
and use it with window.SearchChMap
or if you prefer to load it from your componentDidMount
you can do it like in the snippet below (same code as in the following sandbox ).
It is using onload
of the appended script tag to delay the object creation until the new script is loaded.
The useRef
is used so you can use the created object in other locations of your function (not used in the example).
The useEffect
in the code is required to ensure that the DOM is ready before adding the tag. Same behavior as in class-based components with componentDidMount
lifecycle method. The return of the useEffect
could be used to do cleanup eg return () => { /* remove script tag & dispose the window.SearchChMap */}
(same as 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" }}
/>
);
};
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.