首页 > 解决方案 > 有没有办法在 React 中将纯 HTML 作为单独的组件动态加载?

问题描述

嗨,我试图将烧瓶应用程序与反应前端结合起来。该项目主要专注于使用 pandas 和 matplotlib 等库的数据科学。我试图返回一个与 matplotlib fig 等效的 HTML,并试图在前端呈现它。

由于它是纯 HTML 而不是 JSX,因此当 react 尝试渲染它时会引发错误。在纯 html 设置中运行时,HTML 可以完美运行。我尝试了多个库,但未能在反应基础设置中呈现无花果。

我尝试的另一种方法是创建一个单独的元素,使用文档模型单独呈现 HTML,但由于该图稍后出现,我觉得 dom 不会重新呈现整个页面(我可能在这里错了,但尝试了很长时间并且没有任何效果)。

我尝试渲染的 HTML(这是作为 Post 请求出现的,这就是为什么我觉得不会发生重新渲染,因为当使用文档模型创建元素时它不是反应组件):

<style>

</style>

<div id="fig_el1692823804362488404764011855"></div>
<script>
function mpld3_load_lib(url, callback){
  var s = document.createElement('script');
  s.src = url;
  s.async = true;
  s.onreadystatechange = s.onload = callback;
  s.onerror = function(){console.warn("failed to load library " + url);};
  document.getElementsByTagName("head")[0].appendChild(s);
}

if(typeof(mpld3) !== "undefined" && mpld3._mpld3IsLoaded){
   // already loaded: just create the figure
   !function(mpld3){

       mpld3.draw_figure("fig_el1692823804362488404764011855", {"width": 640.0, "height": 480.0, "axes": [{"bbox": [0.125,
0.10999999999999999, 0.775, 0.77], "xlim": [-0.2, 4.2], "ylim": [0.8, 5.2], "xdomain": [-0.2, 4.2], "ydomain": [0.8, 5.2],
"xscale": "linear", "yscale": "linear", "axes": [{"position": "bottom", "nticks": 11, "tickvalues": null, "tickformat": null, "scale": "linear", "fontsize": 10.0, "grid": {"gridOn": false}, "visible": true}, {"position": "left", "nticks": 11, "tickvalues": null, "tickformat": null, "scale": "linear", "fontsize": 10.0, "grid": {"gridOn": false}, "visible": true}], "axesbg": "#FFFFFF", "axesbgalpha": null, "zoomable": true, "id": "el169282380436246664", "lines": [{"data": "data01", "xindex": 0, "yindex": 1, "coordinates": "data", "id": "el169282380435913992", "color": "#1F77B4", "linewidth": 1.5, "dasharray":
"none", "alpha": 1, "zorder": 2, "drawstyle": "default"}], "paths": [], "markers": [], "texts": [], "collections": [], "images": [], "sharex": [], "sharey": []}], "data": {"data01": [[0.0, 3.0], [1.0, 1.0], [2.0, 4.0], [3.0, 1.0], [4.0, 5.0]]}, "id": "el169282380436248840", "plugins": [{"type": "reset"}, {"type": "zoom", "button": true, "enabled": false}, {"type": "boxzoom", "button": true, "enabled": false}]});
   }(mpld3);
}else if(typeof define === "function" && define.amd){
   // require.js is available: use it to load d3/mpld3
   require.config({paths: {d3: "https://mpld3.github.io/js/d3.v3.min"}});
   require(["d3"], function(d3){
      window.d3 = d3;
      mpld3_load_lib("https://mpld3.github.io/js/mpld3.v0.3.js", function(){

         mpld3.draw_figure("fig_el1692823804362488404764011855", {"width": 640.0, "height": 480.0, "axes": [{"bbox": [0.125, 0.10999999999999999, 0.775, 0.77], "xlim": [-0.2, 4.2], "ylim": [0.8, 5.2], "xdomain": [-0.2, 4.2], "ydomain": [0.8, 5.2], "xscale": "linear", "yscale": "linear", "axes": [{"position": "bottom", "nticks": 11, "tickvalues": null, "tickformat": null, "scale": "linear", "fontsize": 10.0, "grid": {"gridOn": false}, "visible": true}, {"position": "left", "nticks": 11, "tickvalues": null, "tickformat": null, "scale": "linear", "fontsize": 10.0, "grid": {"gridOn": false}, "visible": true}], "axesbg": "#FFFFFF", "axesbgalpha": null, "zoomable": true, "id": "el169282380436246664", "lines": [{"data": "data01", "xindex": 0, "yindex": 1, "coordinates": "data", "id": "el169282380435913992", "color": "#1F77B4", "linewidth": 1.5, "dasharray": "none", "alpha": 1, "zorder": 2, "drawstyle": "default"}], "paths": [], "markers": [], "texts": [], "collections": [], "images": [], "sharex": [], "sharey": []}], "data": {"data01": [[0.0, 3.0], [1.0, 1.0], [2.0, 4.0], [3.0, 1.0], [4.0, 5.0]]}, "id": "el169282380436248840", "plugins": [{"type": "reset"}, {"type": "zoom", "button": true, "enabled": false}, {"type":
"boxzoom", "button": true, "enabled": false}]});
      });
    });
}else{
    // require.js not available: dynamically load d3 & mpld3
    mpld3_load_lib("https://mpld3.github.io/js/d3.v3.min.js", function(){
         mpld3_load_lib("https://mpld3.github.io/js/mpld3.v0.3.js", function(){

                 mpld3.draw_figure("fig_el1692823804362488404764011855", {"width": 640.0, "height": 480.0, "axes": [{"bbox": [0.125, 0.10999999999999999, 0.775, 0.77], "xlim": [-0.2, 4.2], "ylim": [0.8, 5.2], "xdomain": [-0.2, 4.2], "ydomain": [0.8, 5.2], "xscale": "linear", "yscale": "linear", "axes": [{"position": "bottom", "nticks": 11, "tickvalues": null, "tickformat": null, "scale": "linear", "fontsize": 10.0, "grid": {"gridOn": false}, "visible": true}, {"position": "left", "nticks": 11, "tickvalues": null, "tickformat": null, "scale": "linear", "fontsize": 10.0, "grid": {"gridOn": false}, "visible": true}], "axesbg": "#FFFFFF", "axesbgalpha": null, "zoomable": true, "id": "el169282380436246664", "lines": [{"data": "data01", "xindex": 0, "yindex": 1, "coordinates": "data", "id": "el169282380435913992", "color": "#1F77B4", "linewidth": 1.5, "dasharray": "none", "alpha": 1, "zorder": 2, "drawstyle": "default"}], "paths": [], "markers": [], "texts": [], "collections": [], "images": [], "sharex": [], "sharey": []}], "data": {"data01": [[0.0, 3.0], [1.0, 1.0], [2.0, 4.0], [3.0, 1.0], [4.0, 5.0]]}, "id": "el169282380436248840", "plugins": [{"type": "reset"}, {"type": "zoom", "button": true, "enabled": false}, {"type": "boxzoom", "button": true, "enabled": false}]});
            })
         });
}
</script>

我正在尝试的方法是因为我找不到足够好的库来准确地将我的 html 转换为 jsx(如果有这样的 React 库可以转换代码,如果有人可以转换上面的 html 并检查那会很棒):

var App = (props) => {



  const [dataFrameComponent, setDataFrameComponent] = React.useState("");

  useEffect(() => {
    const element = document.getElementById("dataframe");
    if(typeof(element) != 'undefined' && element!= null){

      document.getElementById('dataframe').style.width = "500"
      document.getElementById('dataframe').style.height = "500"

      document.getElementById('dataframe').innerHTML = dataFrameComponent

    }
    else{
      const script = document.createElement("div");
      script.id = 'dataframe'
      script.style.height = '200'
      script.style.width = '200'
      const root = document.getElementById('root')
      root.appendChild(script);
    }
})

const [number, setNumber] = React.useState(0);

  const handleSubmit=(event) => {
    event.preventDefault();
    let formData = new FormData();    //formdata object
    formData.append('number', number);
    console.log(formData);
    console.log(formData.keys())

    fetch('http://127.0.0.1:5000/dataframe',{
      method: 'POST',
      body: formData
    })
    .then((data)=> data.text()).then((data) => setDataFrameComponent(data))

  }



return (
  <div className="App">
    <header className="App-header">
    <form onSubmit={handleSubmit}>
      <label>Enter the number of Elements: </label>
      <input type="text"  name= "number" onChange={(event) => {setNumber(event.target.value)} } />
      <input type="submit" value="Submit" />
    </form>
    </header>
  </div>
);
}


export default App;

我想动态渲染的图形是这样的。https://codepen.io/sherwinfarrell/pen/vYOPBVo

这与我在此处包含的 html 代码相同。

标签: javascriptreactjsmatplotlibmpld3

解决方案


PS谨慎使用这两种方法。

1-您可以使用 createContextualFragment 在没有库的情况下执行此操作:

import React from 'react';

const html = `
  your html here
`;

class App extends React.Component {
  componentDidMount() {
    const wrapper = document.querySelector('#d3_code');
    const range = document.createRange();
    range.setStart(wrapper, 0);
    wrapper.appendChild(
      range.createContextualFragment(html)
    );
  }

  render() {
    return (
      <div>React Snippet</div>
    )
  }
}

export default App;

2- 第二种方法是使用 dangerously-set-html-content 库:

import React from 'react';
import InnerHTML from 'dangerously-set-html-content'
const html = `
  your html here
`;

class App extends React.Component {
  render() {
    return (
      <div>
        <InnerHTML html={html} />
      </div>
    )
  }
}
export default App;

推荐阅读