Tips for incorporating external JavaScript code into React components

I have been tasked with integrating a graphical widget into a React component for a project I am working on. The widget_api code provided by RIPE Stat is required to accomplish this. Previously, in HTML5, the integration was successful using the following code:

<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Widget</title>
</head>
<body>
    
    <script src="https://stat.ripe.net/widgets/widget_api.js"></script>
    <div class="statwdgtauto">
        <script>
            ripestat.init("rir-geo",{"resource":"80.12.67.0/24"},null,{"size":"500","disable":["controls"]})
        </script>
    </div>
</body>
</html>

During my research, I came across the react-safe library which offers a solution for integrating the widget in React. Here is an example of how it can be achieved in a React index file:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.png" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
   
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <title>MyWHOIS</title>
    <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
  </head>
  <body class="bd-home">
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <script src="./js/polyfill.js" defer ></script>
    <script src="https://stat.ripe.net/widgets/widget_api.js" async></script>
  </body>

</html>

Furthermore, I have created a component specifically for embedding the widget:

import React, { Component } from 'react';
import Safe from "react-safe";

export default class EmbedComponent extends Component {
    constructor(props){
        super();
    }

    render() {
        const params1 = {"family":4,"warnings":1,"delegated":1,"resource":"FR"};
        const params2 ={"resource":"127.0.0.1/24"};
        const control = {"size":"500","disable":["controls"]};
        return (
            <div>
                <h4>Include Embed</h4>
                <div className="statwdgtauto">
                    <Safe.script>
                        {`ripestat.init("rpki-by-country",${params1},null,${control})`}
                    </Safe.script>
                    <Safe.script>
                        {`ripestat.init("rir-geo",${params2},null,${control})`}
                    </Safe.script>
                </div>
            </div>
        )
    }
}

When attempting to include the file asynchronously or deferred, I encountered CORS errors. These are the issues I faced:

A parser-blocking, cross site (i.e. different eTLD+1) script, , is invoked via document.write. The network request for this script MAY be blocked by the browser in this or a future page load due to poor network connectivity. If blocked in this page load, it will be confirmed in a subsequent console message. See for more details.

Additionally, without defer or async, attempts to write into the document failed:

Failed to execute 'write' on 'Document': It isn't possible to write into a document from an asynchronously-loaded external script unless it is explicitly opened. widget_api.js:90

Answer №1

Introduce a new state called isLoading

constructor(props) {
    super(props);
    this.state = {
      isLoading: true,
    };
}

componentDidMount() {
  const widget_api = document.createElement("script");
  widget_api.src = "https://stat.ripe.net/widgets/widget_api.js";
  widget_api.async = true;
  // Implement waiting for onload event here
  widget_api.script.onload = () => setState({isLoading: false})
  document.body.appendChild(widget_api);
}

During the isLoading phase, modify your render function to display a loader instead of the current implementation.

Answer №2

One issue at hand is the dependency on a specific implementation detail of the ripeStat library, which hinders its compatibility with modern frameworks like React.

Upon inspecting the code for ripeStat found here: , it becomes evident that it relies on the use of document.write.

The behavior of document.write in deferred situations where it's not supposed to execute can be explored further in this resource: https://developer.mozilla.org/en-US/docs/Web/API/Document/write#notes.

https://i.stack.imgur.com/efiWR.png

Once the document has finished loading, parsing, and closing, any subsequent calls to document.write will not have an effect.

This limitation seems to be intrinsic to the ripeStat library. A more reliable alternative would involve dynamically creating a script element:

const script = document.createElement('script');
script.src = 'https://stat.ripe.net/widgets/widget_api.js';
document.head.appendChild(script);

Implementing such a solution would ensure cross-compatibility with various frameworks.

An additional suggestion would be to provide an npm package for ripeStat that caters specifically to modern frameworks' requirements.

In order for the integration to work seamlessly within a React application, it's imperative that the script containing the required functionality is present before the browser begins interpreting the HTML content.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Encounter issue when using GAS withSuccessHandler function

I've developed a Google Sheets add-on that utilizes a modal dialog for the user interface. I encountered an issue with the success handler not running as expected, so I created a basic test interface to troubleshoot the problem. After the server-side ...

I am looking to show images based on the number chosen from the dropdown menu in CodeIgniter

When a number is selected from the dropdown menu, I want to display images accordingly. The options in the dropdown are 9, 12, and 18. Here is the code snippet for my view page: <form action="<?php echo base_url();?>roxcontrol/numberdisplay" id=" ...

Convert h264 video to GIF using Node.js

Currently, I'm utilizing the "pi-camera" library to successfully record video in a raw h264 format on my Raspberry Pi. However, I am encountering an issue with the node.js library "gifify" which keeps throwing the error "RangeError: Maximum call stack ...

Utilizing Express JS to Optimize JPEG File Loading with Cache Headers

I have been working on implementing Cache-Control for my static image files. I have successfully set this header for HTML and JS files: https://i.stack.imgur.com/9VuWl.png However, I am facing challenges with JPEG files: https://i.stack.imgur.com/p52jm. ...

Fastify endpoint failing to respond to designated URL

Within my code, there is a router setup: fastify.get('/:link', (req, reply) => { req.params.url = req.host+req.url; reply.view("template.ejs",req.params); }); I am trying to capture URLs and process them in the template. All URLs are ...

MongoError: Unknown term '$last' detected ("build version": "5.0.4")

While attempting to aggregate the data I am utilizing MongoDB with version "5.0.4" { $project: { _id: 1, feeling: 1, updated_date: 1, ...

When the browser is not in the foreground, clicking on the Bootstrap datepicker with Selenium does not register

When you click on the input field <input id="dp1" class="span2" type="text" value="02-16-2012"> If the browser is in the background, the datepicker popup will not display. Even using javascript or jquery to click the input field does not show the ...

Angular binding for selecting all data

Upon checking a checkbox for a single item, the bound data is retrieved and added to an array. However, this does not happen when using selectAll. Code snippet in Angular for obtaining the object of a checked item: $scope.selectedOrganisations = []; $sco ...

Blocking negative values when a button is clicked in Vue.js using v-on:click

How can I prevent the counter from going below 0 when clicked in this Vue component? Do I need to create a separate method to block it? Thank you for your assistance. <button v-on:click="counter.document -= 1">-</button> <h3>{{coun ...

Having trouble creating a unit test for exporting to CSV in Angular

Attempting to create a unit test case for the export-to-csv library within an Angular project. Encountering an error where generateCsv is not being called. Despite seeing the code executed in the coverage report, the function is not triggered. Below is the ...

Issue with Chrome not triggering onMouseEnter event when an element blocking the cursor disappears in React

Important Note: This issue seems to be specific to Chrome Currently, React does not trigger the onMouseEnter event when a blocking element disappears. This behavior is different from standard JavaScript events and even delegated events. Below is a simpli ...

Bovine without Redis to oversee queue operations

Can Bull (used for job management) be implemented without utilizing Redis? Here is a segment of my code: @Injectable() export class MailService { private queue: Bull.Queue; private readonly queueName = 'mail'; constructor() { ...

Plot the components of an array and calculate the instances that JavaScript executes

I have an array containing information about PDF files stored in a buffer. Let's imagine this array holds ten PDF files structured like this: [{ correlative: "G-22-1-06", content: <Buffer 25 50 44 46 2d 31 2e 34 0a 25 d3 eb e9 e1 0a ...

What is the best way to automatically run all node.js files within a specific folder upon startup?

Is there a way to automate the running of all node.js scripts within a specific folder on startup, perhaps using an npm script like npm run someScript for each subfolder? Is it possible to achieve this without creating a Java program? ...

Does the onChange event fire when the value is modified by the parent element?

let [number, set_number] = useState({x: 1}); <ChildComponent number={number} onUpdate={onUpdateFunction} </ChildComponent> set_number({x: 2}) After running set_number({x: 2}), will this action prompt the execution of onUpdateFunction refere ...

How to disable scrolling for React components with CSS styling

When incorporating a React component into my HTML, I follow this pattern: <html> <body> <div id=app>${appHtml}</div> <script src="/bundle.js"></script> </body> </html> Within my application, th ...

Sending requests from a React application to a Node.js backend hosted on an Nginx server with SSL enabled

After creating static files for a reactjs app using the create react app tool, I launched an nginx server on a docker container to serve the front end built with reactjs. This nginx server communicates with a node js in another container. Everything was r ...

Submitting a form using jquery

I am working on a project that involves using a jquery fancyzoom box. Within this box, there is a contact form that should send an email upon submission. However, I am encountering issues with calling the form submit function due to the fancyzoom feature. ...

Internet Explorer: JQuery deselects radio button upon its selection

One issue I have encountered is with a listener for a group of radio buttons in IE. When a radio button is selected, it triggers a database call to populate a select element. However, in IE, after the code runs successfully, the selected radio button becom ...

Please provide either a render prop, a render function as children, or a component prop to the Field(auto) component

While working on my project and implementing an Auto complete feature using final-form, I encountered the following error: Must specify either a render prop, a render function as children, or a component prop to Field(auto) In order to resolve this issue ...