Rendern Sie eine HTML-Zeichenfolge als echtes HTML in einer React-Komponente


158

Hier ist, was ich versucht habe und wie es schief geht.

Das funktioniert:

<div dangerouslySetInnerHTML={{ __html: "<h1>Hi there!</h1>" }} />

Das geht nicht:

<div dangerouslySetInnerHTML={{ __html: this.props.match.description }} />

Die Beschreibungseigenschaft ist nur eine normale Zeichenfolge von HTML-Inhalten. Es wird jedoch als Zeichenfolge gerendert, aus irgendeinem Grund nicht als HTML.

Geben Sie hier die Bildbeschreibung ein

Irgendwelche Vorschläge?

Antworten:


50

Überprüfen Sie, ob der Text, den Sie an den Knoten anhängen möchten, nicht wie folgt maskiert wird:

var prop = {
    match: {
        description: '&lt;h1&gt;Hi there!&lt;/h1&gt;'
    }
};

An Stelle von:

var prop = {
    match: {
        description: '<h1>Hi there!</h1>'
    }
};

Wenn es maskiert ist, sollten Sie es von Ihrer Serverseite konvertieren.

Der Knoten ist Text, weil er maskiert ist

Der Knoten ist Text, weil er maskiert ist

Der Knoten ist ein Dom-Knoten, da er nicht maskiert wird

Der Knoten ist ein Dom-Knoten, da er nicht maskiert wird


3
Das war das Problem. Die Beschreibungszeichenfolge wurde in HTML maskiert. Ich habe es entkommen und jetzt funktioniert es gut.
Sergio Tapia

4
Bitte vermeiden Sie die dangerouslySetInnerHTMLVerwendung Fragmentvon React v16. Überprüfen Sie die nächste Antwort von @ brad-adams
Kunal Parekh

2
Schätzen Sie die Erwähnung @KunalParekh, aber es sind verschiedene Dinge. Meine Antwort ist nur gültig, wenn sich das HTML in Ihrer App befindet (was bedeutet, dass es sich tatsächlich um JSX handelt). Um HTML von einer externen Quelle nach jsx zu analysieren, müssen Sie nach einer anderen Lösung suchen.
Brad Adams

113

Enthält this.props.match.descriptionIst ein String oder ein Objekt? Wenn es sich um eine Zeichenfolge handelt, sollte diese problemlos in HTML konvertiert werden. Beispiel:

class App extends React.Component {

constructor() {
    super();
    this.state = {
      description: '<h1 style="color:red;">something</h1>'
    }
  }

  render() {
    return (
      <div dangerouslySetInnerHTML={{ __html: this.state.description }} />
    );
  }
}

ReactDOM.render(<App />, document.getElementById('root'));

Ergebnis: http://codepen.io/ilanus/pen/QKgoLA?editors=1011

Wenn Sie jedoch description: <h1 style="color:red;">something</h1>keine Anführungszeichen ''haben, erhalten Sie:

Object {
$$typeof: [object Symbol] {},
  _owner: null,
  key: null,
  props: Object {
    children: "something",
    style: "color:red;"
  },
  ref: null,
  type: "h1"
}

Wenn es sich um eine Zeichenfolge handelt und Sie kein HTML-Markup sehen, ist das einzige Problem, das ich sehe, ein falsches Markup.

AKTUALISIEREN

Wenn Sie es mit HTMLEntitles zu tun haben. Sie müssen sie entschlüsseln, bevor Sie sie an senden dangerouslySetInnerHTML, deshalb haben sie es gefährlich genannt :)

Arbeitsbeispiel:

class App extends React.Component {

  constructor() {
    super();
    this.state = {
      description: '&lt;p&gt;&lt;strong&gt;Our Opportunity:&lt;/strong&gt;&lt;/p&gt;'
    }
  }

   htmlDecode(input){
    var e = document.createElement('div');
    e.innerHTML = input;
    return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue;
  }

  render() {
    return (
      <div dangerouslySetInnerHTML={{ __html: this.htmlDecode(this.state.description) }} />
    );
  }
}

ReactDOM.render(<App />, document.getElementById('root'));

this.props.match.descriptionist eine Zeichenfolge, kein Objekt. Was meinst du mit falschem Markup? Meinen Sie nicht geschlossene Tags? Reagieren sollte es einfach nicht rendern?
Sergio Tapia

Könnten Sie hier console.log einfügen (this.props.match.description);
Ilanus

Ein Beispiel:&lt;p&gt;&lt;strong&gt;Our Opportunity:&lt;/strong&gt;&lt;/p&gt;
Sergio Tapia

In diesem Fall müssen Sie entweder .innerHTML verwenden oder HTMLEntities dekodieren.
Ilanus

Rückgabe mehrerer Zeilen oder HTML-Code mit Tags: Funktion htmlDecode (Eingabe) {var e = document.createElement ('div'); e.innerHTML = Eingabe; var returnString = ''; for (index = 0; index <e.childNodes.length; index ++) {// Fall nur einer Zeichenfolge if (e.childNodes [index] .nodeValue) {returnString + = e.childNodes [index] .nodeValue; } // Fall von HTML if (e.childNodes [index] .outerHTML) {returnString + = e.childNodes [index] .outerHTML; }} return returnString; }
Chris Adams

58

Ich benutze 'react-html-parser'

yarn add react-html-parser
import ReactHtmlParser from 'react-html-parser'; 

<div> { ReactHtmlParser (html_string) } </div>

Quelle auf npmjs.com

Erhöhen Sie den Kommentar von @ okram für mehr Sichtbarkeit:

Aus der Github-Beschreibung: Konvertiert HTML-Zeichenfolgen direkt in React-Komponenten, ohne dass die gefährliche Verwendung von SetInnerHTML von npmjs.com erforderlich ist. Ein Dienstprogramm zum Konvertieren von HTML-Zeichenfolgen in React-Komponenten. Vermeidet die Verwendung von gefährlichSetInnerHTML und konvertiert Standard-HTML-Elemente, -Attribute und -Inline-Stile in ihre React-Entsprechungen.


10
Verwendet diese Bibliothek im Hintergrund "gefährlichSetInnerHTML"?
Omar

1
von seiner Github-Beschreibung: Converts HTML strings directly into React components avoiding the need to use dangerouslySetInnerHTMLvon npmjs.comA utility for converting HTML strings into React components. Avoids the use of dangerouslySetInnerHTML and converts standard HTML elements, attributes and inline styles into their React equivalents.
okram

14

Wenn Sie die Kontrolle darüber haben, woher die HTML-Zeichenfolge stammt (dh irgendwo in Ihrer App), können Sie von der neuen <Fragment>API profitieren und Folgendes tun:

import React, {Fragment} from 'react'

const stringsSomeWithHtml = {
  testOne: (
    <Fragment>
      Some text <strong>wrapped with strong</strong>
    </Fragment>
  ),
  testTwo: `This is just a plain string, but it'll print fine too`,
}

...

render() {
  return <div>{stringsSomeWithHtml[prop.key]}</div>
}

11
In Ihrem Beispiel gibt es keine Zeichenfolge, die HTML enthält. Es ist entweder jsx oder eine einfache Zeichenfolge.
Mrkvon

3
Nun ja, technisch gesehen haben Sie Recht @mrkvon, aber wie ich bereits erwähne, ist diese Lösung nur gültig, wenn "html" / jsx etwas ist, über das Sie die Kontrolle haben. Nicht zum Rendern von rohem HTML, das beispielsweise über eine API bereitgestellt wird. Vor der FragmentAPI war es für mich immer ein Schmerz, zusätzliche spanWraps zu erfordern , die manchmal mit Flex-Layouts zu tun hatten. Als ich auf diese Frage stieß und nach einer möglichen Lösung suchte, dachte ich, ich würde erzählen, wie ich mit den Dingen umgegangen bin .
Brad Adams

2
Vielen Dank! Dies war die einzige Lösung, die in meinem Fall funktioniert hat. Antwort auf den Kommentar von mrkvon zu dieser Antwort: Diese Antwort enthält tatsächlich HTML, dh Some text <strong>wrapped with strong</strong>enthält HTML-Tag strong.
Binita Bharati

@ BinitaBharati Aber das ist keine Zeichenfolge. Wenn Sie eine Zeichenfolge von einer API wie "<p> Dies ist eine Zeichenfolge </ p>" erhalten (oder einfach eine Zeichenfolge in einer Variablen speichern), enthält die Ausgabe beim Einfügen dieser Zeichenfolge in <Fragment> weiterhin das < p> tag.
Muchdecal

1
@BradAdams. Netter Trick. Ich kann die Fälle sehen, in denen es praktisch wird.
Muchdecal


5

gefährlichSetInnerHTML

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. Sie können HTML also direkt in React festlegen, müssen jedoch gefährlich SetInnerHTML eingeben und ein Objekt mit einem __html-Schlüssel übergeben, um sich daran zu erinnern, dass es gefährlich ist. Beispielsweise:

function createMarkup() {
  return {__html: 'First &middot; Second'};
}

function MyComponent() {
  return <div dangerouslySetInnerHTML={createMarkup()} />;
}

3

Ich benutze innerHTML zusammen, um Folgendes zu überspannen:

import React, { useRef, useEffect, useState } from 'react';

export default function Sample() {
  const spanRef = useRef<HTMLSpanElement>(null);
  const [someHTML,] = useState("some <b>bold</b>");

  useEffect(() => {
    if (spanRef.current) {
      spanRef.current.innerHTML = someHTML;
    }
  }, [spanRef.current, someHTML]);

  return <div>
    my custom text follows<br />
    <span ref={spanRef} />
  </div>
}

Ich mag das, keine Notwendigkeit für zusätzliche Bibliotheken oder Vertrauen auf die Serverseite, wenn Sie diesen Luxus nicht haben. Inspiriert von dir, aber in einer Klassenkomponente, die ich gemacht habe componentDidMount() { this.message.current.innerHTML = this.state.selectedMessage.body; }, ist Body das entkommene HTML für mich.
Webhound

2

In meinem Fall habe ich react-render-html verwendet

Installieren Sie zuerst das Paket von npm i --save react-render-html

dann,

import renderHTML from 'react-render-html';

renderHTML("<a class='github' href='https://github.com'><b>GitHub</b></a>")

1

Ich konnte nicht damit npm buildarbeiten react-html-parser. In meinem Fall konnte ich jedoch https://reactjs.org/docs/fragments.html erfolgreich nutzen . Ich musste einige HTML-Unicode-Zeichen anzeigen, aber sie sollten nicht direkt in JSX eingebettet sein. Innerhalb der JSX musste es aus dem Status der Komponente ausgewählt werden. Das Komponentencode-Snippet ist unten angegeben:

constructor() 
{
this.state = {
      rankMap : {"5" : <Fragment>&#9733; &#9733; &#9733; &#9733; &#9733;</Fragment> , 
                 "4" : <Fragment>&#9733; &#9733; &#9733; &#9733; &#9734;</Fragment>, 
                 "3" : <Fragment>&#9733; &#9733; &#9733; &#9734; &#9734;</Fragment> , 
                 "2" : <Fragment>&#9733; &#9733; &#9734; &#9734; &#9734;</Fragment>, 
                 "1" : <Fragment>&#9733; &#9734; &#9734; &#9734; &#9734;</Fragment>}
                };
}

render() 
{
       return (<div class="card-footer">
                    <small class="text-muted">{ this.state.rankMap["5"] }</small>
               </div>);
}


-2

Wenn Sie die Kontrolle über die {this.props.match.description} haben und JSX verwenden. Ich würde empfehlen, "gefährlichSetInnerHTML" nicht zu verwenden.

// In JSX, you can define a html object rather than a string to contain raw HTML
let description = <h1>Hi there!</h1>;

// Here is how you print
return (
    {description}
);
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.