Rohes HTML mit Reactjs rendern

154

Ist dies also die einzige Möglichkeit, rohes HTML mit Reactjs zu rendern?

// http://facebook.github.io/react/docs/tutorial.html
// tutorial7.js
var converter = new Showdown.converter();
var Comment = React.createClass({
  render: function() {
    var rawMarkup = converter.makeHtml(this.props.children.toString());
    return (
      <div className="comment">
        <h2 className="commentAuthor">
          {this.props.author}
        </h2>
        <span dangerouslySetInnerHTML={{__html: rawMarkup}} />
      </div>
    );
  }
});

Ich weiß, dass es einige coole Möglichkeiten gibt, Dinge mit JSX zu markieren, aber ich bin hauptsächlich daran interessiert, rohes HTML (mit allen Klassen, Inline-Stilen usw.) rendern zu können. So etwas Kompliziertes:

<!-- http://getbootstrap.com/components/#dropdowns-example -->
<div class="dropdown">
  <button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-expanded="true">
    Dropdown
    <span class="caret"></span>
  </button>
  <ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu1">
    <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Action</a></li>
    <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Another action</a></li>
    <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Something else here</a></li>
    <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Separated link</a></li>
  </ul>
</div>

Ich möchte nicht alles in JSX neu schreiben müssen.

Vielleicht denke ich darüber falsch nach. Bitte korrigieren Sie mich.

Vinhboy
quelle
1
Das ist fast JSX. Wenn Sie viel Markup als unformatiertes HTML rendern, verlieren Sie den Vorteil, eine Bibliothek wie React zu verwenden. Ich würde empfehlen, die kleinen Änderungen (wie "Klasse" -> "Klassenname") vorzunehmen, damit React die Elemente handhaben kann.
Ross Allen
2
Für dieses spezielle Beispiel hat bereits jemand die Arbeit für Sie erledigt , die Frage steht jedoch weiterhin für den allgemeinen Fall.
Randy Morris

Antworten:

43

Sie können das html-to-reactnpm-Modul nutzen.

Hinweis: Ich bin der Autor des Moduls und habe es erst vor einigen Stunden veröffentlicht. Bitte melden Sie Fehler oder Usability-Probleme.

Mike Nikles
quelle
24
Verwendet es gefährlichSetInnerHTML intern?
Yash Sharma
2
Ich habe gerade den Code überprüft. Es scheint nicht gefährlich SetInnerHTML zu verwenden.
Ajay Raghav
Mike, warten Sie dieses npm-Modul noch aktiv?
Daniel
Hey Daniel, ich nicht und einer der Mitwirkenden hat es übernommen und die letzte Veröffentlichung vor 7 Monaten veröffentlicht. Siehe github.com/aknuds1/html-to-react
Mike Nikles
Dies verwendet kein gefährlichSetInnerHTML.
Tessaracter
185

Es gibt jetzt sicherere Methoden zum Rendern von HTML. Ich habe dies in einer früheren Antwort hier behandelt . Sie haben 4 Optionen, die zuletzt verwendet werden dangerouslySetInnerHTML.

Methoden zum Rendern von HTML

  1. Am einfachsten - Verwenden Sie Unicode, speichern Sie die Datei als UTF-8 und setzen Sie sie charsetauf UTF-8.

    <div>{'First · Second'}</div>

  2. Sicherer - Verwenden Sie die Unicode-Nummer für die Entität in einer Javascript-Zeichenfolge.

    <div>{'First \u00b7 Second'}</div>

    oder

    <div>{'First ' + String.fromCharCode(183) + ' Second'}</div>

  3. Oder ein gemischtes Array mit Zeichenfolgen und JSX-Elementen.

    <div>{['First ', <span>&middot;</span>, ' Second']}</div>

  4. Letzter Ausweg - Fügen Sie rohes HTML mit ein dangerouslySetInnerHTML.

    <div dangerouslySetInnerHTML={{__html: 'First &middot; Second'}} />

Brett DeWoody
quelle
Alles was ich brauche ist 3 oder 4
Nicolas S.Xu
dangerouslySetInnerHTMLIch frage mich, was andere Attribute außer __html erhalten
Juan Solano
30
Ich liebe diesen Thread ... Implizit: "Tu was immer du kannst, um # 4 nicht zu verwenden". Alle: "# 4 hat super funktioniert!"
deepelement
1
@JuanSolano keine, gemäß den automatisch vervollständigten Einträgen in einer TypeScript-Umgebung.
Andreas Linnert
In einer ähnlichen Frage, stackoverflow.com/questions/19266197/… , hat diese Antwort nicht allzu gut funktioniert. Vielleicht passt es besser zu dieser Frage oder vielleicht lesen die Leute die Antwort nicht ...: D
425nesp
27

Ich habe dies in schnellen und schmutzigen Situationen verwendet:

// react render method:

render() {
    return (
      <div>
        { this.props.textOrHtml.indexOf('</') !== -1
            ? (
                <div dangerouslySetInnerHTML={{__html: this.props.textOrHtml.replace(/(<? *script)/gi, 'illegalscript')}} >
                </div>
              )
            : this.props.textOrHtml
          }

      </div>
      )
  }
Cory Robinson
quelle
7
Dies ist nicht sicher - was ist, wenn der HTML-Code enthält <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" onload="alert('test');">?
Yjwong
11
Es ist sicher, wenn Sie die Kontrolle über das gerenderte HTML haben
John
18

Ich habe diese reine Komponente ausprobiert:

const RawHTML = ({children, className = ""}) => 
<div className={className}
  dangerouslySetInnerHTML={{ __html: children.replace(/\n/g, '<br />')}} />

Eigenschaften

  • Nimmt classNameRequisite (einfacher zu stylen)
  • Ersetzt \nzu <br />(das möchten Sie oft tun)
  • Platzieren Sie Inhalte als untergeordnete Elemente, wenn Sie die Komponente wie folgt verwenden:
  • <RawHTML>{myHTML}</RawHTML>

Ich habe die Komponente in einem Gist bei Github platziert: RawHTML: ReactJS reine Komponente zum Rendern von HTML

Netsi1964
quelle
12
export class ModalBody extends Component{
    rawMarkup(){
        var rawMarkup = this.props.content
        return { __html: rawMarkup };
    }
    render(){
        return(
                <div className="modal-body">
                     <span dangerouslySetInnerHTML={this.rawMarkup()} />

                </div>
            )
    }
}
Jozcar
quelle
Die obige Arbeit für mich, ich habe HTML an Modal Body übergeben.
Jozcar
11

gefährlichSetInnerHTML ist Reacts Ersatz für die Verwendung von innerHTML im Browser-DOM. Im Allgemeinen ist das Festlegen von HTML aus Code riskant, da es leicht ist, Ihre Benutzer versehentlich einem XSS-Angriff (Cross-Site Scripting) auszusetzen.

Es ist besser / sicherer, Ihren Roh-HTML-Code (z. B. DOMPurify) zu bereinigen, bevor Sie ihn über in das DOM einfügen dangerouslySetInnerHTML.

DOMPurify - ein DOM- reiner , superschneller, überaus toleranter XSS-Desinfektionsdienst für HTML, MathML und SVG. DOMPurify arbeitet mit einem sicheren Standard, bietet jedoch viel Konfigurierbarkeit und Hooks.

Beispiel :

import React from 'react'
import createDOMPurify from 'dompurify'
import { JSDOM } from 'jsdom'

const window = (new JSDOM('')).window
const DOMPurify = createDOMPurify(window)

const rawHTML = `
<div class="dropdown">
  <button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-expanded="true">
    Dropdown
    <span class="caret"></span>
  </button>
  <ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu1">
    <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Action</a></li>
    <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Another action</a></li>
    <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Something else here</a></li>
    <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Separated link</a></li>
  </ul>
</div>
`

const YourComponent = () => (
  <div>
    { <div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(rawHTML) }} /> }
  </div>
)

export default YourComponent
Yuci
quelle
Genau das habe ich in dieser Antwort gesucht. Es sollte mehr positive
Stimmen
6

Ich habe diese Bibliothek namens Parser verwendet . Es funktionierte für das, was ich brauchte.

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

class MyComponent extends Component {
  render() {
    <div>{Parser(this.state.message)}</div>
  }
};
Ecairol
quelle
3
21 KB (8 KB gezippt). Ich konnte das für Browser-Code nicht rechtfertigen.
Peter Bengtsson
Diese Bibliothek bricht meine Expo-App
ekkis
5

dangerouslySetInnerHTMLsollte nicht verwendet werden, es sei denn, dies ist unbedingt erforderlich. Nach der Dokumentation, „Dies vor allem für die mit String - Manipulation Bibliotheken DOM zusammenarbeiten“ . Wenn Sie es verwenden, geben Sie die Vorteile der DOM-Verwaltung von React auf.

In Ihrem Fall ist die Konvertierung in eine gültige JSX-Syntax ziemlich einfach. Ändern Sie einfach die classAttribute in className. Wie in den obigen Kommentaren erwähnt, können Sie auch die ReactBootstrap- Bibliothek verwenden, die Bootstrap-Elemente in React-Komponenten kapselt.

Breno Ferreira
quelle
8
Danke für deine Antwort. Ich verstehe die Sicherheitsauswirkungen der Verwendung von innerHTML und weiß, dass ich es in JSX konvertieren kann. Ich frage jedoch speziell nach der Unterstützung von React für die Verwendung von rohen HTML-Snippets.
Vinhboy
Was genau meinen Sie mit "Reacts Unterstützung für die Verwendung von rohen HTML-Snippets"?
Breno Ferreira
2

Hier ist eine etwas weniger einfühlsame Version der zuvor veröffentlichten RawHTML-Funktion. Es lässt Sie:

  • Konfigurieren Sie das Tag
  • Optional ersetzen Sie Zeilenumbrüche durch <br /> 's
  • Übergeben Sie zusätzliche Requisiten, die RawHTML an das erstellte Element weitergibt
  • Geben Sie eine leere Zeichenfolge ein ( RawHTML></RawHTML>)

Hier ist die Komponente:

const RawHTML = ({ children, tag = 'div', nl2br = true, ...rest }) =>
    React.createElement(tag, {
        dangerouslySetInnerHTML: {
            __html: nl2br
                ? children && children.replace(/\n/g, '<br />')
                : children,
        },
        ...rest,
    });
RawHTML.propTypes = {
    children: PropTypes.string,
    nl2br: PropTypes.bool,
    tag: PropTypes.string,
};

Verwendung:

<RawHTML>{'First &middot; Second'}</RawHTML>
<RawHTML tag="h2">{'First &middot; Second'}</RawHTML>
<RawHTML tag="h2" className="test">{'First &middot; Second'}</RawHTML>
<RawHTML>{'first line\nsecond line'}</RawHTML>
<RawHTML nl2br={false}>{'first line\nsecond line'}</RawHTML>
<RawHTML></RawHTML>

Ausgabe:

<div>First · Second</div>
<h2>First · Second</h2>
<h2 class="test">First · Second</h2>
<div>first line<br>second line</div>
<div>first line
second line</div>
<div></div>

Es wird weiter brechen:

<RawHTML><h1>First &middot; Second</h1></RawHTML>
Christiaan Westerbeek
quelle
0

Ich musste einen Link mit dem onLoad-Attribut in meinem Kopf verwenden, wo div nicht erlaubt ist, was mir erhebliche Schmerzen verursachte. Meine aktuelle Problemumgehung besteht darin, das ursprüngliche Skript-Tag zu schließen, das zu tun, was ich tun muss, und dann das Skript-Tag zu öffnen (um vom Original geschlossen zu werden). Hoffe, dies könnte jemandem helfen, der absolut keine andere Wahl hat:

<script dangerouslySetInnerHTML={{ __html: `</script>
   <link rel="preload" href="https://fonts.googleapis.com/css?family=Open+Sans" as="style" onLoad="this.onload=null;this.rel='stylesheet'" crossOrigin="anonymous"/>
<script>`,}}/>
Adam Lane
quelle