Editar 2015
Alguém fez um projeto no NPM com minha solução: https://github.com/lovasoa/react-contenteditable
Editar 06/2016: Acabei de encontrar um novo problema que ocorre quando o navegador tenta "reformatar" o html que você acabou de fornecer a ele, levando a um componente sempre re-renderizado. Vejo
Editar 07/2016: aqui está minha implementação de produção de contentEditable. Ele tem algumas opções adicionais react-contenteditable
que você pode desejar, incluindo:
- trancando
- API imperativa que permite incorporar fragmentos html
- capacidade de reformatar o conteúdo
Resumo:
A solução do FakeRainBrigand funcionou muito bem para mim por algum tempo, até que encontrei novos problemas. ContentEditables são uma dor e não são realmente fáceis de lidar com React ...
Este JSFiddle demonstra o problema.
Como você pode ver, ao digitar alguns caracteres e clicar em Clear
, o conteúdo não é apagado. Isso ocorre porque tentamos redefinir o contenteditable para o último valor dom virtual conhecido.
Então, parece que:
- Você precisa
shouldComponentUpdate
evitar saltos na posição do cursor
- Você não pode confiar no algoritmo de comparação VDOM do React se usar
shouldComponentUpdate
desta forma.
Portanto, você precisa de uma linha extra para que, sempre que shouldComponentUpdate
retornar sim, você tenha certeza de que o conteúdo DOM está realmente atualizado.
Portanto, a versão aqui adiciona um componentDidUpdate
e se torna:
var ContentEditable = React.createClass({
render: function(){
return <div id="contenteditable"
onInput={this.emitChange}
onBlur={this.emitChange}
contentEditable
dangerouslySetInnerHTML={{__html: this.props.html}}></div>;
},
shouldComponentUpdate: function(nextProps){
return nextProps.html !== this.getDOMNode().innerHTML;
},
componentDidUpdate: function() {
if ( this.props.html !== this.getDOMNode().innerHTML ) {
this.getDOMNode().innerHTML = this.props.html;
}
},
emitChange: function(){
var html = this.getDOMNode().innerHTML;
if (this.props.onChange && html !== this.lastHtml) {
this.props.onChange({
target: {
value: html
}
});
}
this.lastHtml = html;
}
});
O Dom virtual permanece desatualizado e pode não ser o código mais eficiente, mas pelo menos funciona :) Meu bug foi resolvido
Detalhes:
1) Se você colocar shouldComponentUpdate para evitar saltos circunflexos, o contenteditable nunca será processado novamente (pelo menos nas teclas)
2) Se o componente nunca for renderizado novamente no pressionamento de tecla, o React manterá um dom virtual desatualizado para este conteúdo editável.
3) Se o React mantiver uma versão desatualizada do conteúdo editável em sua árvore de dom virtual, se você tentar redefinir o conteúdo editável para o valor desatualizado no dom virtual, durante a comparação do dom virtual, o React calculará que não há alterações em aplique ao DOM!
Isso acontece principalmente quando:
- você tem um conteúdo editável vazio inicialmente (shouldComponentUpdate = true, prop = "", vdom anterior = N / A),
- o usuário digita algum texto e você evita renderizações (shouldComponentUpdate = false, prop = text, vdom anterior = "")
- depois que o usuário clica em um botão de validação, você deseja esvaziar esse campo (shouldComponentUpdate = false, prop = "", vdom anterior = "")
- como os novos e antigos vdom são "", React não toca no dom.
initialValue
emstate
e usá-lo emrender
, mas eu não deixo Reagir atualização ainda mais.