React.js: imposta innerHTML vs dangerouslySetInnerHTML


171

C'è qualche differenza "dietro le quinte" rispetto all'impostazione dell'HTML interno di un elemento rispetto all'impostazione della proprietà dangerouslySetInnerHTML su un elemento? Supponiamo che sto disinfettando correttamente le cose per semplicità.

Esempio:

var test = React.createClass({
  render: function(){
    return (
      <div contentEditable='true' dangerouslySetInnerHTML={{ __html: "Hello" }}></div>
    );
  }
});

vs

var test = React.createClass({
  componentDidUpdate: function(prevProp, prevState){
    this.refs.test.innerHTML = "Hello";
  },
  render: function(){
    return (
      <div contentEditable='true' ref='test'></div>
    );
  }
});

Sto facendo qualcosa di un po 'più complicato dell'esempio sopra, ma l'idea generale è la stessa

Risposte:


237

Sì, c'è differenza!

L'effetto immediato dell'uso innerHTMLcontro dangerouslySetInnerHTMLè identico: il nodo DOM verrà aggiornato con l'HTML iniettato.

Tuttavia , dietro le quinte quando lo usi dangerouslySetInnerHTML, fa sapere a React che l'HTML all'interno di quel componente non è qualcosa a cui tiene.

Dato che React usa un DOM virtuale, quando va a confrontare il diff con il DOM attuale, può andare direttamente in bypass controllando i figli di quel nodo perché sa che l'HTML proviene da un'altra fonte . Quindi ci sono miglioramenti delle prestazioni.

Ancora più importante , se si utilizza semplicemente innerHTML, React non ha modo di sapere che il nodo DOM è stato modificato. Alla successiva renderchiamata della funzione, React sovrascriverà il contenuto che è stato iniettato manualmente con quello che pensa dovrebbe essere lo stato corretto di quel nodo DOM.

La tua soluzione da utilizzare componentDidUpdateper garantire sempre che il contenuto sia sincronizzato credo che funzionerebbe ma potrebbe esserci un lampo durante ogni rendering.


11
Ho scritto un piccolo test perf non scientifico per mostrare la differenza tra allineare un SVG e usare dangerouslySetInnerHTML: webpackbin.com/bins/-KepHa-AMxQgGxOUnAac - tira fuori il metodo innerHTML è quasi due volte più veloce (vedi console nel webpackbin)
Joscha

4
È vero e facile da prevedere. Poiché innerHTML è un metodo nativo che lega il codice SVG direttamente al DOM senza considerare nulla. D'altra parte, pericolosamenteSetInnerHTML è il metodo che deriva da React che il codice SVG deve essere analizzato come figli di React Component prima di metterli sul DOM virtuale e quindi renderizzarli sul DOM.
Fino al

3

Secondo Dangerously Set innerHTML ,

L'uso improprio di innerHTMLpuò aprirti a un attacco di cross-site scripting (XSS) . La sanificazione dell'input dell'utente per la visualizzazione è notoriamente soggetta a errori e la mancata corretta sanificazione è una delle principali cause di vulnerabilità del Web su Internet.

La nostra filosofia di progettazione è che dovrebbe essere "facile" rendere le cose sicure e gli sviluppatori dovrebbero dichiarare esplicitamente il loro intento quando eseguono operazioni "non sicure". Il nome dell'elica dangerouslySetInnerHTMLviene scelto intenzionalmente come spaventoso e il valore dell'elica (un oggetto anziché una stringa) può essere usato per indicare dati sterilizzati.

Dopo aver compreso appieno le implicazioni di sicurezza __htmle aver disinfettato correttamente i dati, creare un nuovo oggetto contenente solo la chiave e i dati disinfettati come valore. Ecco un esempio usando la sintassi JSX:

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

<div dangerouslySetInnerHTML={createMarkup()} /> 

Leggi di più a riguardo usando il link seguente:

documentazione : React DOM Elements - dangerouslySetInnerHTML .


1
Questo non risponde alla domanda.
Quentin

2

Basato su ( dangerouslySetInnerHTML ).

È un oggetto che fa esattamente quello che vuoi. Comunque lo chiamano per indicare che dovrebbe essere usato con cautela


1
bene secondo i documenti sembra che questa sia l'unica ragione, ancora confusa
mkb
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.