swartchris8
swartchris8

Reputation: 720

Rendering static page (javascript + html) response from API in React

Is there a way to render an html + javascript response from an API in React?

Based on this question I can render html with dangerouslySetInnerHTML={html}. My problem is the html response from the API also contains javascript as it is a vega visualisation.

Placing my whole static page into public as a file works with <a href="vega_example.html">Redirect to Html page</a>. The disadvantage of this redirect is that I don't want to save a file for every API response.

Is there a way I can render a string as a static html page with React without saving it in a file?

App.js to render static page using the public file in public folder

import React, { useEffect, useState } from 'react';

function MyComponent() {
    
  const [html, setHTML] = useState({__html: ""});

  useEffect(() => {
    async function createMarkup() {
      const backendHtmlString = `<a href="vega_example.html">Redirect to Html page</a>`

       console.log(backendHtmlString)
        return {__html: backendHtmlString};
     }
     
     createMarkup().then(result => setHTML(result));
  }, []);

  return <div dangerouslySetInnerHTML={html} />;
}

function App() {
  return (
    <div className="App">
        <MyComponent/>
    </div>
  );
}

export default App;

In public I have vega_example.html which is pretty much my API response

<!DOCTYPE html>
<html>
<head>
  <script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
  <script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
  <script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
</head>
<body>
  <div id="vis"/>
  <script>
    const spec = {
  "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
  "description": "A simple bar chart with embedded data.",
  "data": {
    "values": [
      {"a": "A", "b": 28},
      {"a": "B", "b": 55},
      {"a": "C", "b": 43},
      {"a": "D", "b": 91},
      {"a": "E", "b": 81},
      {"a": "F", "b": 53},
      {"a": "G", "b": 19},
      {"a": "H", "b": 87},
      {"a": "I", "b": 52}
    ]
  },
  "mark": "bar",
  "encoding": {
    "x": {"field": "a", "type": "nominal", "axis": {"labelAngle": 0}},
    "y": {"field": "b", "type": "quantitative"}
  },
  "config": {}
};
    vegaEmbed("#vis", spec, {mode: "vega-lite"}).then(console.log).catch(console.warn);
  </script>
</body>
</html>

Upvotes: 0

Views: 864

Answers (1)

Lupina
Lupina

Reputation: 780

Answering your literal question, you could either:

  • Render the content to an iFrame (the rendering being done by JavaScript calls, not React calls)
  • (Would strongly recommend against) Use RegEx to extract the contents of <script/> and use eval to run that JavaScript

However, I would instead recommend either:

  • Assuming the API only serves the JSON data, render the #vis element with React, load the JSON data in the hook, and then run vegaEmbed directly at the end of the hook.
  • If the API is dynamic, simply link to the API directly and let it serve the HTML dynamically instead of saving it as a file.

Upvotes: 1

Related Questions