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.


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.


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'}} />


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

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


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

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

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

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.


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>

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>`,}}/>
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.