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?

Sergio Tapia
quelle

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

Sergio Flores
quelle
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'));
Ilanus
quelle
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.

Pixelerd
quelle
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>
}
Brad Adams
quelle
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
6

Sie verwenden nur die gefährlich-SetInnerHTML-Methode von React

<div dangerouslySetInnerHTML={{ __html: htmlString }} />

Oder Sie können auf einfache Weise mehr implementieren: Rendern Sie den HTML-Code in der React-App

Hou Soune
quelle
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()} />;
}
مهدی عابدی برنامه نویس و مشاور
quelle
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>
}
Lorenzo Delana
quelle
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>")
Salman Lone
quelle
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>);
}
Binita Bharati
quelle
0

Ich benutze https://www.npmjs.com/package/html-to-react

const HtmlToReactParser = require('html-to-react').Parser;
let htmlInput = html.template;
let htmlToReactParser = new HtmlToReactParser();
let reactElement = htmlToReactParser.parse(htmlInput); 
return(<div>{reactElement}</div>)
Янов Алексей
quelle
-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}
);
BBRay
quelle