Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to use a CDN inside a React component

I found a similar question, but didn't understand any of the answers (and the question was downvoted) So here I go:

I'm trying to use a library built on D3, called Greuler, in order to dynamically render graphs. The npm package for it seems to be broken. When I switched out for the Greuler CDN, the test graph inside my index.html finally worked.

However, I'm working on a React app, and I want the graph to be rendered from a React component. Here the problem comes up: the react component doesn't use the Greuler CDN scripts that are in my index.html, and I've tried multiple ways of running the scripts inside my component, but nothing seems to work.

The two main errors are:

error 'greuler' is not defined (in my component)

Uncaught TypeError: Cannot read property 'getAttribute' of null (in the D3 code)

My working index.html, with hard-coded graph looks like:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Navigating Spinoza</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.js"></script>
    <script src="http://marvl.infotech.monash.edu/webcola/cola.v3.min.js"></script>
    <script src="http://maurizzzio.github.io/greuler/greuler.min.js"></script>
  </head>
  <body>
    <div id="root"></div>
    <div class="row" id="demo">
      <script>
        var instance = greuler({
          target: '#demo',
          width: 480,
          height: 500,
          data: {
            nodes: [
              {id: 0, label: "E1Def3", r: 25},
              {id: 1, label: "E1P4", r: 15},
              {id: 2, label: "E1P2", r: 15},
              {id: 3, label: "E1P1", r: 15},
              {id: 4, label: "E1P5", r: 15},
              {id: 5, label: "E1P6", r: 25}
            ],
            links: [
              {source: 0, target: 1, directed: true},
              {source: 0, target: 2, directed: true},
              {source: 0, target: 3, directed: true},
              {source: 1, target: 4, directed: true},
              {source: 2, target: 5, directed: true},
              {source: 3, target: 4, directed: true},
              {source: 4, target: 5, directed: true}
            ]
          }
        }).update()
      </script>
    </div>
  </body>
</html>

My last desperate attempt at the render function in the component looks like:

render() {
    return (
     <div class="row" id="demo">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.js"></script>
    <script src="http://marvl.infotech.monash.edu/webcola/cola.v3.min.js"></script>
    <script src="http://maurizzzio.github.io/greuler/greuler.min.js"></script>
     { 
        greuler({
          target: '#demo',
          width: 480,
          height: 500,
          data: {
            nodes: [
              {id: 0, label: "E1Def3", r: 25},
              {id: 1, label: "E1P4", r: 15},
              {id: 2, label: "E1P2", r: 15},
              {id: 3, label: "E1P1", r: 15},
              {id: 4, label: "E1P5", r: 15},
              {id: 5, label: "E1P6", r: 25}
            ],
            links: [
              {source: 0, target: 1, directed: true},
              {source: 0, target: 2, directed: true},
              {source: 0, target: 3, directed: true},
              {source: 1, target: 4, directed: true},
              {source: 2, target: 5, directed: true},
              {source: 3, target: 4, directed: true},
              {source: 4, target: 5, directed: true}
            ]
          }
        }).update()
      }
    </div>
      </div>
    );
  }
}
like image 540
jaimefps Avatar asked May 02 '17 21:05

jaimefps


2 Answers

The best/simplest solution would be to have a stub index.html file which includes the scripts that you need (you could install libraries from npm as others has suggested, however this will work for libraries which only have a CDN). Thus you would have an index.html file like this:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Navigating Spinoza</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.js"></script>
    <script src="http://marvl.infotech.monash.edu/webcola/cola.v3.min.js"></script>
    <script src="http://maurizzzio.github.io/greuler/greuler.min.js"></script>
  </head>
  <body>
    <div id="root"></div>
    <div class="row" id="demo"></div>
  </body>
</html>

And then a react component like like this (I have moved some code around to better follow some react idioms):

var Component = React.createClass({    
  componentDidMount:function() {
    greuler({
      target: '#chart',
      width: 480,
      height: 500,
      data: {
        nodes: [
          {id: 0, label: "E1Def3", r: 25},
          {id: 1, label: "E1P4", r: 15},
          {id: 2, label: "E1P2", r: 15},
          {id: 3, label: "E1P1", r: 15},
          {id: 4, label: "E1P5", r: 15},
          {id: 5, label: "E1P6", r: 25}
        ],
        links: [
          {source: 0, target: 1, directed: true},
          {source: 0, target: 2, directed: true},
          {source: 0, target: 3, directed: true},
          {source: 1, target: 4, directed: true},
          {source: 2, target: 5, directed: true},
          {source: 3, target: 4, directed: true},
          {source: 4, target: 5, directed: true}
        ]
      }
    }).update()
  }

  render() {
    return (
      <div id="chart"></div>
    );
  }
}

ReactDOM.render(<Component />, document.querySelector('root'));

This is a simple solution that could stand to do more (such as use react's state and properties to pass around parameters) but this should give a general idea of the solution. This code also assumes that you have included the React and ReactDOM libraries in some way (babel, CDN, etc.).

like image 193
Jordan Avatar answered Nov 07 '22 03:11

Jordan


Try this:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Navigating Spinoza</title>
</head>
<body>
<div id="root"></div>
<div class="row" id="demo"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.js">
</script>
<script src="http://marvl.infotech.monash.edu/webcola/cola.v3.min.js">
</script>
<script src="http://maurizzzio.github.io/greuler/greuler.min.js"></script>
<script>
    import React from 'react'
    import { render } from 'react-dom'

    var Instance = greuler({
      target: '#demo',
      width: 480,
      height: 500,
      data: {
        nodes: [
          {id: 0, label: "E1Def3", r: 25},
          {id: 1, label: "E1P4", r: 15},
          {id: 2, label: "E1P2", r: 15},
          {id: 3, label: "E1P1", r: 15},
          {id: 4, label: "E1P5", r: 15},
          {id: 5, label: "E1P6", r: 25}
        ],
        links: [
          {source: 0, target: 1, directed: true},
          {source: 0, target: 2, directed: true},
          {source: 0, target: 3, directed: true},
          {source: 1, target: 4, directed: true},
          {source: 2, target: 5, directed: true},
          {source: 3, target: 4, directed: true},
          {source: 4, target: 5, directed: true}
        ]
      }
    }).update()

    render(
      <Instance />,
      document.getElementById('root')
    )
  </script>
</body>
</html>
like image 29
JuMoGar Avatar answered Nov 07 '22 02:11

JuMoGar