Rendering di html non elaborato con reazioni


154

Quindi è questo l'unico modo per eseguire il rendering di HTML html con un reattore?

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

So che ci sono alcuni modi fantastici per eseguire il markup delle cose con JSX, ma sono principalmente interessato a essere in grado di eseguire il rendering di HTML html (con tutte le classi, gli stili incorporati, ecc.). Qualcosa di complicato come questo:

<!-- 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>

Non vorrei riscrivere tutto ciò in JSX.

Forse sto pensando a questo tutto sbagliato. Per favore, correggimi.


1
Questo è quasi JSX. Se esegui il rendering di molti markup come HTML non elaborato, perdi il vantaggio di utilizzare una libreria come React. Consiglio di fare le piccole modifiche (come "class" -> "className") per consentire a React di gestire gli elementi.
Ross Allen,

2
Per questo esempio specifico qualcuno ha già fatto il lavoro per te , tuttavia la domanda rappresenta ancora il caso generale.
Randy Morris,

Risposte:


43

È possibile sfruttare il html-to-reactmodulo npm.

Nota: sono l'autore del modulo e l'ho appena pubblicato poche ore fa. Non esitate a segnalare eventuali bug o problemi di usabilità.


24
usa pericolosamenteSetInnerHTML internamente?
Yash Sharma,

2
Ho appena controllato il codice. Non sembra usare pericolosamente SetInnerHTML.
Ajay Raghav,

Mike, stai ancora mantenendo attivamente questo modulo npm?
Daniel,

Ehi Daniel, io no e uno dei collaboratori ha preso il controllo e pubblicato l'ultima versione 7 mesi fa. Vedi github.com/aknuds1/html-to-react
Mike Nikles l'

Questo non utilizza alcun pericolosamenteSetInnerHTML.
Tessaracter,

185

Esistono ora metodi più sicuri per il rendering HTML. Ho coperto questo in una risposta precedente qui . Hai 4 opzioni, l'ultima utilizza dangerouslySetInnerHTML.

Metodi per il rendering HTML

  1. Più semplice : utilizzare Unicode, salvare il file come UTF-8 e impostare charsetUTF-8.

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

  2. Più sicuro : utilizzare il numero Unicode per l'entità all'interno di una stringa Javascript.

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

    o

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

  3. O un array misto con stringhe ed elementi JSX.

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

  4. Last Resort : inserisci HTML non elaborato utilizzando dangerouslySetInnerHTML.

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


Tutto ciò di cui ho bisogno è 3 o 4
Nicolas S.Xu

chiedendosi quali altri attributi riceve dangerouslySetInnerHTMLoltre a __html
Juan Solano,

30
Adoro questi thread ... Implicitamente: "Fai tutto il possibile per non usare # 4". Tutti: "# 4 ha funzionato alla grande!"
deepelement

1
@JuanSolano nessuno, secondo le voci di completamento automatico in un ambiente TypeScript.
Andreas Linnert,

In una domanda simile, stackoverflow.com/questions/19266197/… , questa risposta non ha funzionato troppo bene. Forse è più adatto a questa domanda o forse le persone non leggono la risposta ...: D
425nesp

27

L'ho usato in situazioni veloci e sporche:

// 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
Questo non è sicuro: cosa succede se l'HTML contiene <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" onload="alert('test');">?
yjwong,

11
È sicuro se hai il controllo del rendering dell'HTML
John

18

Ho provato questo componente puro:

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

Caratteristiche

  • Prende classNameprop (più facile da modellare)
  • Sostituisce \na <br />(spesso vogliono fare quello)
  • Posiziona i contenuti come bambini quando usi il componente come:
  • <RawHTML>{myHTML}</RawHTML>

Ho inserito il componente in Gist in Github: RawHTML: componente puro di ReactJS per eseguire il rendering 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>
            )
    }
}

Il lavoro sopra per me, stavo passando html al corpo modale.
Jozcar,

12

dangerouslySetInnerHTML è il sostituto di React per l'utilizzo di innerHTML nel DOM del browser. In generale, impostare HTML dal codice è rischioso perché è facile esporre inavvertitamente gli utenti a un attacco di cross-site scripting (XSS).

È meglio / più sicuro disinfettare il tuo HTML non elaborato (usando ad esempio DOMPurify) prima di iniettarlo nel DOM tramite dangerouslySetInnerHTML.

DOMPurify - un disinfettante XSS solo DOM, superveloce e super tollerante per HTML, MathML e SVG. DOMPurify funziona con un valore predefinito sicuro, ma offre molta configurabilità e hook.

Esempio :

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

Questo è esattamente quello che stavo cercando in questa risposta. Dovrebbe avere più voti
llamerr

6

Ho usato questa libreria chiamata Parser . Ha funzionato per quello che mi serviva.

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 in formato zip). Non potrei giustificarlo per il codice del browser.
Peter Bengtsson,

questa libreria rompe la mia app Expo
ekkis il

5

dangerouslySetInnerHTMLnon dovrebbe essere usato se non assolutamente necessario. Secondo i documenti, "Questo è principalmente per cooperare con le librerie di manipolazione di stringhe DOM" . Quando lo usi, stai rinunciando al vantaggio della gestione DOM di React.

Nel tuo caso, è abbastanza semplice convertire in sintassi JSX valida; basta cambiare gli classattributi in className. Oppure, come menzionato nei commenti sopra, è possibile utilizzare la libreria ReactBootstrap che incapsula gli elementi Bootstrap nei componenti di React.


8
Grazie per la tua risposta. Comprendo le implicazioni di sicurezza dell'utilizzo di innerHTML e so di poterlo convertire in JSX. Ma sto specificatamente chiedendo il supporto di React per l'utilizzo di frammenti HTML grezzi.
Vinhboy,

Cosa intendi esattamente con "Supporto di React per l'utilizzo di frammenti HTML grezzi"?
Breno Ferreira,

2

Ecco una versione un po 'meno supponente della funzione RawHTML pubblicata in precedenza. Ti permette di:

  • configura il tag
  • facoltativamente sostituire le nuove righe a <br />'s
  • passare ulteriori oggetti di scena che RawHTML passerà all'elemento creato
  • fornire una stringa vuota ( RawHTML></RawHTML>)

Ecco il componente:

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

Uso:

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

Produzione:

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

Si interromperà:

<RawHTML><h1>First &middot; Second</h1></RawHTML>

0

Avevo bisogno di utilizzare un link con l'attributo onLoad nella mia testa in cui div non è permesso, quindi questo mi ha causato un dolore significativo. La mia soluzione attuale è chiudere il tag di script originale, fare quello che devo fare, quindi aprire il tag di script (per essere chiuso dall'originale). Spero che questo possa aiutare qualcuno che non ha assolutamente altra scelta:

<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>`,}}/>
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.