React.js: Définissez innerHTML vs dangerouslySetInnerHTML

172

Existe-t-il une différence «en coulisse» entre la définition de innerHTML d'un élément et la définition de la propriété dangerouslySetInnerHTML sur un élément? Supposons que je désinfecte correctement les choses dans un souci de simplicité.

Exemple:

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

contre

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

Je fais quelque chose d'un peu plus compliqué que l'exemple ci-dessus, mais l'idée générale est la même

Jshoe523
la source

Réponses:

238

Oui, il y a une différence!

L'effet immédiat de l'utilisation de innerHTMLversus dangerouslySetInnerHTMLest identique - le nœud DOM se mettra à jour avec le HTML injecté.

Cependant , dans les coulisses lorsque vous l'utilisez dangerouslySetInnerHTML, React sait que le HTML à l'intérieur de ce composant n'est pas quelque chose qui l'intéresse.

Parce que React utilise un DOM virtuel, quand il va comparer le diff avec le DOM réel, il peut contourner directement la vérification des enfants de ce nœud car il sait que le HTML provient d'une autre source . Il y a donc des gains de performances.

Plus important encore , si vous utilisez simplement innerHTML, React n'a aucun moyen de savoir que le nœud DOM a été modifié. La prochaine fois que la renderfonction sera appelée, React écrasera le contenu qui a été injecté manuellement avec ce qu'il pense que l'état correct de ce nœud DOM devrait être.

Votre solution à utiliser componentDidUpdatepour toujours s'assurer que le contenu est synchronisé, je pense, fonctionnerait, mais il pourrait y avoir un flash lors de chaque rendu.

Francis John
la source
11
J'ai écrit un petit test de perf non scientifique pour montrer la différence entre l'inclusion d'un SVG et l'utilisation de dangerouslySetInnerHTML: webpackbin.com/bins/-KepHa-AMxQgGxOUnAac - la méthode innerHTML est presque deux fois plus rapide (voir console dans le webpackbin)
Joscha
4
C'est vrai et facile à prévoir. Depuis innerHTML est une méthode native qui lie le code SVG directement au DOM sans rien considérer. D'autre part, dangerouslySetInnerHTML est la méthode venue de React dans laquelle le code SVG doit être analysé en tant qu'enfants React Component avant de les placer dans le DOM virtuel puis de le rendre dans le DOM.
Up209d
3

Selon InnerHTML Dangerously Set ,

Mauvaise utilisation du innerHTML peut vous ouvrir à une attaque de script intersite (XSS) . La désinfection des entrées utilisateur pour l'affichage est notoirement sujette aux erreurs, et le fait de ne pas nettoyer correctement est l'une des principales causes de vulnérabilités Web sur Internet.

Notre philosophie de conception est qu'il devrait être «facile» de sécuriser les choses, et les développeurs devraient explicitement indiquer leur intention lorsqu'ils effectuent des opérations «non sécurisées». Le nom de l'accessoire dangerouslySetInnerHTMLest délibérément choisi pour être effrayant, et la valeur de l'accessoire (un objet au lieu d'une chaîne) peut être utilisée pour indiquer des données nettoyées.

Après avoir bien compris les ramifications de sécurité et avoir correctement nettoyé les données, créez un nouvel objet contenant uniquement la clé __htmlet vos données nettoyées comme valeur. Voici un exemple utilisant la syntaxe JSX:

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

<div dangerouslySetInnerHTML={createMarkup()} /> 

En savoir plus à ce sujet en utilisant le lien ci-dessous:

documentation : React DOM Elements - dangerouslySetInnerHTML .

Ganesh Sanap
la source
1
Cela ne répond pas à la question.
Quentin le
2

Basé sur ( dangerouslySetInnerHTML ).

C'est un accessoire qui fait exactement ce que vous voulez. Cependant, ils le nomment pour indiquer qu'il doit être utilisé avec prudence

Jason
la source
1
eh bien selon la documentation, il semble que ce soit la seule raison, encore confuse
mkb