React.js: definir innerHTML vs dangerousouslySetInnerHTML

171

Existe alguma diferença "nos bastidores" entre definir o innerHTML de um elemento e definir a propriedade dangerouslySetInnerHTML em um elemento? Suponha que eu esteja higienizando adequadamente as coisas por uma questão de simplicidade.

Exemplo:

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

Estou fazendo algo um pouco mais complicado que o exemplo acima, mas a ideia geral é a mesma

Jshoe523
fonte

Respostas:

237

Sim, há uma diferença!

O efeito imediato do uso innerHTMLversus dangerouslySetInnerHTMLé idêntico - o nó DOM será atualizado com o HTML injetado.

No entanto , nos bastidores quando você o usa dangerouslySetInnerHTML, o React sabe que o HTML dentro desse componente não é algo com o que se importa.

Como o React usa um DOM virtual, quando ele compara o diff com o DOM real, ele pode ignorar diretamente a verificação dos filhos desse nó, porque sabe que o HTML é proveniente de outra fonte . Portanto, há ganhos de desempenho.

Mais importante , se você simplesmente usar innerHTML, o React não terá como saber se o nó do DOM foi modificado. Na próxima vez que a renderfunção for chamada, o React substituirá o conteúdo que foi injetado manualmente pelo que ele acha que deveria ser o estado correto desse nó DOM.

Sua solução a ser usada componentDidUpdatepara garantir sempre que o conteúdo esteja sincronizado, acredito que funcionaria, mas pode haver um flash durante cada renderização.

Francis John
fonte
11
Eu escrevi um pequeno teste de desempenho não científico para mostrar a diferença entre inline um SVG e usar dangerouslySetInnerHTML: webpackbin.com/bins/-KepHa-AMxQgGxOUnAac - remove o método innerHTML é quase duas vezes mais rápido (consulte o console no webpackbin)
Joscha
4
Isso é verdade e fácil de prever. Como innerHTML é um método nativo que liga o código SVG diretamente ao DOM sem considerar nada. Por outro lado, DangerouslySetInnerHTML é o método proveniente do React, que o código SVG deve ser analisado como filho do React Component antes de colocá-los no DOM virtual e renderizar no DOM.
2020:
3

De acordo com Dangerously Set innerHTML ,

O uso inadequado do innerHTMLpode abrir um ataque XSS (cross-site scripting) . A limpeza da entrada do usuário para exibição é notoriamente suscetível a erros, e a falha na limpeza adequada é uma das principais causas de vulnerabilidades da Web na Internet.

Nossa filosofia de design é que deve ser "fácil" tornar as coisas seguras, e os desenvolvedores devem declarar explicitamente sua intenção ao executar operações "inseguras". O nome do suporte dangerouslySetInnerHTMLé intencionalmente escolhido para ser assustador, e o valor do suporte (um objeto em vez de uma string) pode ser usado para indicar dados higienizados.

Depois de entender completamente as ramificações de segurança e limpar adequadamente os dados, crie um novo objeto que contenha apenas a chave __htmle seus dados higienizados como valor. Aqui está um exemplo usando a sintaxe JSX:

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

<div dangerouslySetInnerHTML={createMarkup()} /> 

Leia mais sobre isso usando o link abaixo:

documentação : Reagir elementos DOM - dangerousouslySetInnerHTML .

Ganesh Sanap
fonte
1
Isso não responde à pergunta.
Quentin
2

Baseado em ( dangerouslySetInnerHTML ).

É um suporte que faz exatamente o que você deseja. No entanto, eles o nomeiam para transmitir que deve ser usado com cautela

Jason
fonte
1
bem de acordo com docs parece que esta é a única razão, ainda confuso
mkb