Modifier 2015
Quelqu'un a réalisé un projet sur NPM avec ma solution: https://github.com/lovasoa/react-contenteditable
Edit 06/2016: Je viens de rencontrer un nouveau problème qui se produit lorsque le navigateur essaie de "reformater" le html que vous venez de lui donner, conduisant à un re-rendu des composants. Voir
Edit 07/2016: voici mon contenu de production Implémentation modifiable. Il propose des options supplémentaires react-contenteditable
que vous pourriez souhaiter, notamment:
- verrouillage
- API impérative permettant d'incorporer des fragments html
- possibilité de reformater le contenu
Résumé:
La solution de FakeRainBrigand a très bien fonctionné pour moi pendant un certain temps jusqu'à ce que j'aie de nouveaux problèmes. ContentEditables est pénible, et n'est pas vraiment facile à gérer avec React ...
Ce JSFiddle illustre le problème.
Comme vous pouvez le voir, lorsque vous tapez des caractères et cliquez sur Clear
, le contenu n'est pas effacé. C'est parce que nous essayons de réinitialiser le contenteditable à la dernière valeur de dom virtuelle connue.
Il semble donc que:
- Vous devez
shouldComponentUpdate
éviter les sauts de position du curseur
- Vous ne pouvez pas compter sur l'algorithme de différence VDOM de React si vous utilisez
shouldComponentUpdate
cette méthode.
Vous avez donc besoin d'une ligne supplémentaire pour que chaque fois que shouldComponentUpdate
retourne oui, vous soyez sûr que le contenu DOM est réellement mis à jour.
Donc la version ici ajoute un componentDidUpdate
et devient:
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;
}
});
Le dom virtuel reste obsolète, et ce n'est peut-être pas le code le plus efficace, mais au moins ça marche :) Mon bogue est résolu
Détails:
1) Si vous mettez shouldComponentUpdate pour éviter les sauts de curseur, alors les contenteditable ne sont jamais renvoyés (au moins sur les frappes)
2) Si le composant ne se rend jamais sur un coup de touche, React conserve un dom virtuel obsolète pour ce contenu modifiable.
3) Si React conserve une version obsolète du contenteditable dans son arborescence de dom virtuel, alors si vous essayez de réinitialiser le contenteditable à la valeur obsolète dans le dom virtuel, alors pendant la différence de dom virtuel, React calculera qu'il n'y a pas de changement dans postulez au DOM!
Cela se produit principalement lorsque:
- vous avez un contenu vide initialement modifiable (shouldComponentUpdate = true, prop = "", previous vdom = N / A),
- l'utilisateur tape du texte et vous empêchez les rendus (shouldComponentUpdate = false, prop = text, previous vdom = "")
- après que l'utilisateur clique sur un bouton de validation, vous souhaitez vider ce champ (shouldComponentUpdate = false, prop = "", previous vdom = "")
- comme le vdom nouvellement produit et l'ancien sont "", React ne touche pas le dom.
initialValue
enstate
et l' utiliser dansrender
, mais je ne laisse pas React jour davantage.