web-dev-qa-db-fra.com

React: Combien puis-je manipuler le DOM React a rendu?

C'est ce que je fais: jsfiddle

La section critique est:

position: function() {
  var container = $(this.getDOMNode());
  this._menu = $(this.refs.menu.getDOMNode());
  this._menu.appendTo(document.body).
      offset({
          top: container.offset().top + 
              container.outerHeight(),
          left: container.offset().left
      });
},
restore: function() {
  this._menu.appendTo(this.getDOMNode());      
},
componentWillUpdate: function() {
  this.restore();
},
componentDidUpdate: function() {
  this.position();
},
componentDidMount: function() {
  this.position();
},

Cela fonctionne très bien en ce moment. Je remets le contenu avant les mises à jour du composant en supposant que React laisse le DOM seul entre les mises à jour et ne le manquera pas. En fait, React semble être bien avec le déplacement de contenu (si je supprime componentWillUpdate et componentDidUpdate, l'élément positionné est toujours mis à jour!)

Ma question est de savoir combien d'hypothèses résultantes sont sûres (c.-à-d., Si je suppose ces choses, mon code se cassera-t-il dans une future version de React?):

  • React ne se soucie pas si DOM est déplacé entre les mises à jour tant que vous le remettez dans componentWillUpdate.
  • Les gestionnaires d'événements React fonctionneront toujours sur les éléments qui ont été déplacés.
  • React fusionnera tous les styles en ligne que vous lui demandez avec les styles déjà présents sur l'élément (même s'il ne les a pas définis.)
  • React mettra à jour le DOM qu'il a rendu, même si vous déplacez ce DOM ailleurs dans le document!

Le dernier me semble quelque peu extrême et magique, mais a de grandes implications s'il tient.

61
noah

Je suis un React dev. Je vais répondre à chacune de vos questions:


React ne se soucie pas si DOM est déplacé entre les mises à jour tant que vous le remettez dans componentWillUpdate.

Vrai - React ne regarde pas le DOM sauf lors de la mise à jour, à l'exception des gestionnaires d'événements:

Les gestionnaires d'événements React fonctionneront toujours sur les éléments qui ont été déplacés.

Je ne compterais pas là-dessus, et je ne suis pas sûr que ce soit encore vrai maintenant.

React fusionnera tous les styles en ligne que vous lui demandez avec les styles déjà présents sur l'élément (même s'il ne les a pas définis.)

Je ne compterais pas non plus là-dessus - en ce moment React définit les propriétés individuelles mais je pourrais facilement imaginer qu'il définisse el.style.cssText Si c'était plus rapide, ce qui ferait sauter les changements individuels qui vous avez fait.

React mettra à jour le DOM qu'il a rendu, même si vous déplacez ce DOM ailleurs dans le document!

Je ne crois pas que ce soit vrai actuellement et vous ne devriez pas non plus vous en remettre à cela.


D'une manière générale, vous ne devez pas manipuler à la main le DOM créé par React. Il est 100% casher de créer un <div> Vide dans React = et remplissez-le à la main; il est même correct de modifier les propriétés d'un élément rendu par React tant que vous n'essayez pas plus tard de changer ses propriétés dans React (provoquant React pour effectuer des mises à jour DOM), mais si vous déplacez un élément, React peut le rechercher et être confus lorsqu'il ne le trouve pas.

J'espère que ça t'as aidé.

60
Sophie Alpert

D'une part, je conviens avec Sophie que vous ne devez pas baser vos décisions sur les détails de la mise en œuvre. Cependant, je dirais qu'il est toujours intéressant de voir comment React fonctionne réellement:

Certaines choses ont peut-être changé un peu, mais c'est généralement ce qui se passe et comment cela se produit.

  1. Considérez le fait que React place des identifiants uniques (maintenant des attributs de données) sur chaque élément DOM qu'il crée. Ces identifiants sont actuellement basés sur un système très simple. Cela devrait expliquer le système - Le nœud racine est toujours '.0'

               .0
        .0.0        .0.1
    .0.0.0     .0.1.0 .0.1.1
    

Chaque fois que vous fournissez un attribut "clé", la valeur que vous fournissez est utilisée pour l'ID plutôt que pour son index dans une liste, mais le système reste le même.

  1. Le DOM virtuel créé par React a également des objets légers avec les mêmes identifiants. Il s'agit du système de mappage simple entre le DOM virtuel et le DOM réel.

  2. C'est également la raison pour laquelle les éléments d'une liste sont remplacés si vous ne fournissez pas l'attribut "clé" car l'id des éléments changerait si un élément était ajouté ou supprimé au milieu de la liste.

Gardant cela à l'esprit:

React ne se soucie pas si DOM est déplacé entre les mises à jour tant que vous le remettez dans componentWillUpdate.

Oui. Je pense qu'il est possible que les choses fonctionnent même si vous ne remettez pas l'élément avant les mises à jour, car React fonctionne avec des identifiants. Mais ce serait très délicat et peu fiable à travailler car des éléments peuvent être ajoutés ou supprimés et les choses peuvent se briser.

Les gestionnaires d'événements React fonctionneront toujours sur les éléments qui ont été déplacés.

Oui ... dans une certaine mesure. La façon dont les gestionnaires d'événements réagissent est que tous les événements sont synthétiques. Cela signifie qu'il n'y a qu'un seul écouteur d'événements sur le noeud DOM racine React. Tous les événements capturés sont comparés aux auditeurs d'événements dans React. Je pense que cela utilise également des identifiants pour faire correspondre les éléments. Cependant, React peut effectuer une vérification minimale de ses éléments parents. Je pense que cela devrait fonctionner tant que l'élément est conservé dans le même nœud racine rendu par React. Cela dit, React pourrait mettre à jour le système d'identification à l'avenir et faire plus de vérification des nœuds parents à l'avenir, ce qui pourrait alors se casser.

React fusionnera tous les styles en ligne que vous lui demandez avec les styles déjà présents sur l'élément (même s'il ne les a pas définis.)

Cela a déjà été répondu. Fonctionne pour l'instant, peut ne pas fonctionner à l'avenir. Je ne pense pas que cela changera à court terme, car certains systèmes d'animation dépendent de ce détail d'implémentation.

React mettra à jour le DOM qu'il a rendu, même si vous déplacez ce DOM ailleurs dans le document!

Oui, si vous conservez le même élément DOM avec le même react-id, react ne saura pas qu'il a bougé dans le document et le mettra juste à jour comme s'il était dans la même position où il l'a rendu. Comme vous l'avez déjà remarqué, il doit être dans la même racine React. Ceci est important, car React se lie uniquement au noeud DOM racine React pour les événements synthétiques, etc. De cette façon, React fonctionne bien avec d'autres bibliothèques et n'a pas besoin d'accéder à la racine du document .

Attention: ce n'est pas parce que vous pouvez faire quelque chose que vous devez le faire. De manière générale, vous ne devez ajouter que des nœuds DOM supplémentaires et ajouter des propriétés sur les nœuds DOM qui ne sont pas gérés par React (style: les valeurs de transformation sont courantes pour les animations). Lorsque vous faites d'autres choses, comprenez que les choses peuvent fonctionner, mais il existe généralement une bien meilleure façon de faire les choses.


Quant à votre problème:

Alors, comment résoudriez-vous mon problème? par exemple, un menu déroulant à l'intérieur d'une zone de défilement coupé par le débordement ... J'ai toujours déplacé l'élément vers le corps, mais il semble que ce ne soit pas la façon React.

Je pense que la situation idéale ici est de mettre la liste déroulante dans le corps pour commencer. Ensuite, vous pouvez passer des messages entre l'événement de clic et le menu déroulant. Soit vous pouvez utiliser des rappels pour aller assez haut sur le DOM virtuel, puis mettre à jour les accessoires jusqu'au menu déroulant pour gérer son état. OR utilisez simplement un bon vieux système d'événements.

17
Naman Goel