React.js: Establezca innerHTML vs dangerouslySetInnerHTML

171

¿Hay alguna diferencia "detrás de escena" de configurar el innerHTML de un elemento frente a configurar la propiedad peligrosamenteSetInnerHTML en un elemento? Supongamos que estoy desinfectando adecuadamente las cosas por simplicidad.

Ejemplo:

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

Estoy haciendo algo un poco más complicado que el ejemplo anterior, pero la idea general es la misma.

Jshoe523
fuente

Respuestas:

237

¡Sí, hay una diferencia!

El efecto inmediato de usar innerHTMLversus dangerouslySetInnerHTMLes idéntico: el nodo DOM se actualizará con el HTML inyectado.

Sin embargo , entre bastidores cuando lo usa dangerouslySetInnerHTMLle permite a React saber que el HTML dentro de ese componente no es algo que le importe.

Debido a que React usa un DOM virtual, cuando se compara el diff con el DOM real, puede pasar directamente por alto a los elementos secundarios de ese nodo porque sabe que el HTML proviene de otra fuente . Entonces hay ganancias de rendimiento.

Más importante aún , si simplemente usa innerHTML, React no tiene forma de saber que el nodo DOM ha sido modificado. La próxima vez renderque se llame a la función, React sobrescribirá el contenido que se inyectó manualmente con lo que cree que debería ser el estado correcto de ese nodo DOM.

componentDidUpdateCreo que su solución para usar siempre para garantizar que el contenido esté sincronizado funcionaría, pero podría haber un flash durante cada render.

Francis John
fuente
11
Escribí una prueba de Potencia pequeña, no científico para mostrar la diferencia entre un inlining SVG y el uso de dangerouslySetInnerHTML: webpackbin.com/bins/-KepHa-AMxQgGxOUnAac - toneles a cabo el método innerHTML es casi dos veces más rápido (ver la consola en el webpackbin)
Joscha
44
Eso es cierto y fácil de predecir. Dado que innerHTML es un método nativo que une el código SVG directamente al DOM sin considerar nada. Por otro lado, peligrosamenteSetInnerHTML es el método que proviene de React, que el código SVG debe analizarse como elementos secundarios React Component antes de ponerlos en DOM virtual y luego procesarlos en DOM.
Up209d
3

Según Dangerously Set innerHTML ,

El uso incorrecto del innerHTMLpuede abrirlo a un ataque de scripting entre sitios (XSS) . La desinfección de la entrada del usuario para la visualización es notoriamente propensa a errores, y la falta de desinfección adecuada es una de las principales causas de vulnerabilidades web en Internet.

Nuestra filosofía de diseño es que debe ser "fácil" hacer que las cosas sean seguras, y los desarrolladores deben declarar explícitamente su intención al realizar operaciones "inseguras". El nombre del accesorio dangerouslySetInnerHTMLse elige intencionalmente para ser aterrador, y el valor del accesorio (un objeto en lugar de una cadena) se puede usar para indicar datos desinfectados.

Después de comprender completamente las ramificaciones de seguridad y desinfectar adecuadamente los datos, cree un nuevo objeto que contenga solo la clave __htmly sus datos desinfectados como valor. Aquí hay un ejemplo usando la sintaxis JSX:

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

<div dangerouslySetInnerHTML={createMarkup()} /> 

Lea más sobre esto usando el siguiente enlace:

documentación : React DOM Elements - dangerouslySetInnerHTML .

Ganesh Sanap
fuente
1
Esto no responde la pregunta.
Quentin
2

Basado en ( dangerouslySetInnerHTML ).

Es un accesorio que hace exactamente lo que quieres. Sin embargo, lo nombran para transmitir que debe usarse con precaución

Jason
fuente
1
bueno, según los documentos, parece que esta es la única razón, todavía confundida
mkb