web-dev-qa-db-ja.com

HTMLを含むStringをReact Componentsに解析する方法

このライブラリを使用しています: _html-to-react_ HTMLをReactコンポーネントの文字列として「コンパイル」することが可能であることがわかりました。

私たちはウィジェットに基づいたシステムを行っており、それらは時間の経過とともに変化する可能性があります(つまり、追加/削除/更新/など)。

HTMLを使用して簡単なウィジェットを作成しましたが、クリックイベントに応答するためにこのウィジェットを試しているので、HTMLからonclick=method()メソッドまたはReactから_onClick={method}_を追加することを考えました。ただし、ブラウザのコンソールでこれらのエラーが発生するため、目的の出力を取得できませんでした。

_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)
_

私が使用しているコードは次のとおりです。

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;
_

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;
_

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"
  }
}
_

上記のライブラリを使用してHTMLをReactコンポーネントに解析することで、alertまたは類似のものを取得できますか?もしそうなら、どうすればいいですか?それとも私は何を間違えていますか?


編集

特に使用しているライブラリである必要はありません。別のライブラリを使用して同様の作業を行った場合は、この推奨事項を受け入れることができます(注、ソフトウェアまたはライブラリを要求していません、ただし、HTMLまたは回避策を含むString内でonClickメソッドを呼び出す方法)


編集2

何かを試した後、この行を削除することがわかりました:

_var reactHtml = ReactDOMServer.renderToStaticMarkup(reactElement);
_

メッセージの1つを取り除きます。ライブラリはその要素を使用して、現在の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)
_

編集3

いくつかの調査の後、 dangerousSetInnerHTML in this answer を見つけました。

その後、次のように この回答 HTML内にalertを配置しようとしました。

_'<label htmlFor="float-input" onclick="alert(\'Hello\')">Hello2</label>'
_

そして、それはalertをトリガーしましたが、下のコードのようにmyFunctionを宣言した場合(クラスの外側、クラス内、および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;
_

しかし、今回は新しいエラーが発生します:

_ReferenceError: myFunction is not defined[Learn More]
_

私は同様の質問を見つけました: この問題について、dangerouslySetInnerHTML/regular html内の<a>タグのonClickを処理する を調べ、もう少し調べてみました このコメント which dangerouslySetInnerHTMLからのイベントはこの方法でトリガーされないことを示し、 docs にリンクします。

したがって、これはalertメソッドから直接書き込まれたときにonclickを取得したときの回避策のように見えましたが、おそらくより多くの経験を持つ人ができる場合は正しい方法でそれをしませんでしたそれを試して明確にし、素晴らしいだろう。


編集4

この方法でalertを表示する方法を見つけました。

  • HTMLを文字列として書く
  • dangerouslySetInnerHTMLを介してHTMLを設定します
  • ReactからのcomponentDidMound()関数で、純粋なJavascriptを使用してonclick関数を追加します。
  • 成功

ただし、私たちがやろうとしているのはです:

  • いくつかのメソッドを作成します。例えば:addTwoNumbersまたはそのようなもの
  • onclick関数を呼び出すHTML文字列内からonClickまたはaddTwoNumbersを送信します。
  • addTwoNumbersメソッドを使用する必要がある新しいコンポーネントを追加する必要があるたびに繰り返し、そのためのHTMLを記述し、データベースに保存して取得し、それを使用するだけです。

何かのようなもの:

_...
    <label onClick={myFunction}> My Label </label>
...
_

または上で言ったように:

_...
    <label onClick={addTwoNumbers}> My Label </label>
...
_

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;
_

これを念頭に置いて、私がやろうとしていることを行う他の方法を知っていますか?

15
Frakcool

解決策は少しハックです、コードサンドボックスにコピーアンドペースト

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>
    );
  }
}
3
Rahil Ahmad

特定のケースで機能するかどうかはわかりませんが、HTMLを解析することはまったく考えていません。 webpackに、さまざまなファイルのセットに対して個別のバンドルを生成するように指示できます。今、私はこれをやったことはありませんが、できることを何度か読みました。たとえば、 this です。

次に、サイトのすべての部分が変更されていないmain.bundle.jsを作成します。また、変更可能なすべてのウィジェットに対してwidget1.bundle.jsなどを作成します。それらをすべてindex.htmlにインポートします。次に、小さなバンドル(widget1など)をキャッシュしないようにWebサーバーを構成します。ユーザーがWebサイトに入るたびに、それらのウィジェットが再度ダウンロードされ、効果的に更新されます。さらに豪華にしたい場合は、各ウィジェットの現在のバージョンをAPIに提供し、そのバージョンのウィジェットバンドルに追加のフィールドを追加して、コンポーネントが最新かどうかを定期的に確認できます。ユーザーがしばらくの間ページをリロードしなかったというイベント。古くなったコンポーネントを発見した場合は、強制的にリロードするだけで、ブラウザは最新バージョンを取得します。

私はこれがあなたが行くものとは完全に異なるパスであることを知っていますが、それがあなたの特定のケースに適している場合、それは手作業でhtmlを解析し、すべてのリクエストを自分で処理します。

0
Luan Nico