如何将包含HTML的String解析为React Components

Fra*_*ool 15 html javascript parsing reactjs

我正在使用这个库:html-to-react因为我发现可以将HTML"编译"为反应组件的字符串.

我们正在做一个基于小部件的系统,它们可能会随着时间而改变(即添加/删除/更新/等),因此我们计划将小部件HTML从数据库发送到前端,这是使用React完成的.

我已经使用HTML成功完成了一个简单的小部件,现在我正在尝试使用这个小部件来响应点击事件,所以我想onclick=method()从HTML或onClick={method}React 添加方法.但是我无法获得所需的输出,因为我在浏览器的控制台中收到了这些错误.

Warning: Invalid event handler property `onclick`. React events use the camelCase naming convention, for example `onClick`.
    in label
    in span
    in div
Warning: Invalid event handler property `onclick`. Did you mean `onClick`?
    in label
    in span
    in div
    in DireccionComponent (at App.js:51)
    in div (at App.js:50)
    in GridItem (created by ReactGridLayout)
    in div (created by ReactGridLayout)
    in ReactGridLayout (at App.js:49)
    in App (at index.js:11)
Run Code Online (Sandbox Code Playgroud)

我正在使用的代码如下:

App.js

import React, { Component } from 'react';
import './App.css';
import DireccionComponent from './DireccionComponent.js';

class App extends Component {
    render() {
        return (
            <DireccionComponent />
        );
    }
}

export default App;
Run Code Online (Sandbox Code Playgroud)

DireccionComponent.js

import React, {Component} from 'react';

var ReactDOMServer = require('react-dom/server');
var HtmlToReactParser = require('html-to-react').Parser;

let htmlInput = ''
            +   '<div>'
            +       '<center><label className="title">Widget</label></center>'
            +       '<span className="ui-float-label">'
            +           '<label htmlFor="float-input" onClick={this.myFunction}>Hello</label>'
            +       '</span>'
            +   '</div>';

var htmlToReactParser = new HtmlToReactParser();
var reactElement = htmlToReactParser.parse(htmlInput);
var reactHtml = ReactDOMServer.renderToStaticMarkup(reactElement);

class DireccionComponent extends Component {
    constructor(props) {
        super (props);

        this.myFunction = this.myFunction.bind(this);
    }

    render() {
        return (
            reactElement
        )
    }

    myFunction() {
        console.log('Hola');
        alert("Hola");
    }
}

export default DireccionComponent;
Run Code Online (Sandbox Code Playgroud)

的package.json

{
  "name": "my-app",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "html-to-react": "^1.3.3",
    "primereact": "^1.5.1",
    "react": "^16.3.2",
    "react-dom": "^16.3.2",
    "react-dom-server": "0.0.5",
    "react-grid-layout": "^0.16.6",
    "react-scripts": "1.1.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  }
}
Run Code Online (Sandbox Code Playgroud)

是否有可能alert使用上面的库来解析HTML到React Components?如果是的话,我怎么能这样做?或者我做错了什么?


编辑

它不一定是我正在使用的库,如果有另一个你曾经使用并做过类似的事情,我愿意接受这个建议(注意,我不是要求一个软件或库,但如何调用onClick包含我的HTML或变通方法的String内的方法)


编辑2

在尝试了一些东西后,我发现删除了这一行:

var reactHtml = ReactDOMServer.renderToStaticMarkup(reactElement);
Run Code Online (Sandbox Code Playgroud)

删除其中一条消息.该库使用该元素来测试当前HTML和解析的HTML是否相同.我没有为我的情况需要它,但仍然在控制台中留下当前错误:

 Warning: Invalid event handler property `onclick`. Did you mean `onClick`?
    in label
    in span
    in div
    in DireccionComponent (at App.js:47)
    in App (at index.js:11)
Run Code Online (Sandbox Code Playgroud)

编辑3

经过一番调查,我dangerousSetInnerHTML这个答案中找到了

然后我试着按照这个答案放在alert我的HTML里面,如下所示:

'<label htmlFor="float-input" onclick="alert(\'Hello\')">Hello2</label>'
Run Code Online (Sandbox Code Playgroud)

并且它触发了alert,但是如果我myFunction在下面的代码中声明(注意我试图将它声明为function类外部,在它内部并且也作为var myFunction = function() { ... }一起并且分开):

import React, {Component} from 'react';

var ReactDOMServer = require('react-dom/server');
var HtmlToReactParser = require('html-to-react').Parser;

let htmlInput = ''
            //+ '<div>'
            +       '<center><label className="title">Widget</label></center>'
            +       '<span className="ui-float-label">'
            +           '<label htmlFor="float-input" onclick="myFunction()">Hello2</label>'
            +       '</span>'
            //+     '</div>';

var htmlToReactParser = new HtmlToReactParser();
var reactElement = htmlToReactParser.parse(htmlInput);

class DireccionComponent extends Component {
    constructor(props) {
        super (props);

        this.myFunction = this.myFunction.bind(this);
    }

    render() {
        return (
            <div dangerouslySetInnerHTML={{__html: htmlInput}}>

            </div>
        )
    }

    myFunction() {
        console.log('Hola');
        alert("Hola");
    }
}

function myFunction() {
    console.log('Hola');
    alert("Hola");
}

export default DireccionComponent;
Run Code Online (Sandbox Code Playgroud)

但这次我收到一个新错误:

ReferenceError: myFunction is not defined[Learn More]
Run Code Online (Sandbox Code Playgroud)

我发现了一个类似的问题:使用此问题处理危险的SetInnerHTML /常规html中的<a>标签onClick,并尝试进行更多调查并发现此评论说明来自的事件dangerouslySetInnerHTML不会被触发,链接到文档.

所以,虽然这似乎是一个解决方法,当我得到一个alert直接从onclick方法写,或者可能我没有以正确的方式做,所以如果有经验的人可以尝试并澄清,将是伟大的.


编辑4

我找到了一种以alert这种方式展示的方法:

  • 将HTML写为字符串
  • 通过设置HTML dangerouslySetInnerHTML
  • componentDidMound()React的函数上使用纯Javascript来添加onclick函数.
  • 成功

但是,我们要做的是:

  • 创建一些方法,例如:addTwoNumbers或类似的东西
  • 在HTML字符串调用函数中发送onclick或发送.onClickaddTwoNumbers
  • 每次我们需要添加一个需要使用该addTwoNumbers方法的新组件时重复,只需要为它编写HTML,将其保存在数据库中并检索它然后只使用它.

就像是:

...
    <label onClick={myFunction}> My Label </label>
...
Run Code Online (Sandbox Code Playgroud)

或者正如我上面所说:

...
    <label onClick={addTwoNumbers}> My Label </label>
...
Run Code Online (Sandbox Code Playgroud)

允许我获取的代码alert如下:

import React, {Component} from 'react';
import Parser from 'html-react-parser';
import {render} from 'react-dom';

var ReactDOMServer = require('react-dom/server');
var HtmlToReactParser = require('html-to-react').Parser;

let htmlInput = ''
            //+ '<div>'
            +       '<center><label className="title">Widget</label></center>'
            +       '<span className="ui-float-label">'
            +           '<label htmlFor="float-input" id="myLabel">Hello2</label>'
            +       '</span>'
            //+     '</div>';

var htmlToReactParser = new HtmlToReactParser();
var reactElement = htmlToReactParser.parse(htmlInput);

class DireccionComponent extends Component {
    constructor(props) {
        super (props);

        this.myFunction = this.myFunction.bind(this);
    }

    render() {
        return (
            <div dangerouslySetInnerHTML={{__html: htmlInput}}>

            </div>
        )
    }

    componentDidMount() {
        console.log('DONE');

        let myLabel = document.getElementById("myLabel");

        myLabel.onclick = function() {
            alert();
            console.log('clicked');
        }
        console.log(myLabel);
    }

    myFunction() {
        console.log('Hola');
        alert("Hola");
    }
}

function myFunction() {
    console.log('Hola');
    alert("Hola");
}

export default DireccionComponent;
Run Code Online (Sandbox Code Playgroud)

考虑到这一点,您是否知道其他任何方式来做我想做的事情?

Rah*_*mad 8

解决方案有点hacky,复制粘贴到codeandbox

class App extends Component {
  constructor(props) {
    super(props);
    this.myfunc = this.myfunc.bind(this);
  }
  componentDidMount() {
    window.myfunc = this.myfunc;
  }
  myfunc() {
    console.log("from myfunc");
  }
  componentWillUnmount() {
    window.myfunc = null;
  }
  render() {
    let inputhtml = "<a onclick=window.myfunc()>HelloWorld</a>";
    return (
      <div style={styles}>
        <div dangerouslySetInnerHTML={{ __html: inputhtml }} />
      </div>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)