Maison > interface Web > js tutoriel > Une introduction détaillée aux composants contrôlés et non contrôlés dans React

Une introduction détaillée aux composants contrôlés et non contrôlés dans React

亚连
Libérer: 2018-06-15 14:47:47
original
1479 Les gens l'ont consulté

Cet article présente principalement les composants contrôlés et non contrôlés de la programmation approfondie de React. Maintenant, je le partage avec vous et le donne comme référence.

Il n'y a pas beaucoup d'informations sur les composants contrôlés et les composants non contrôlés sur le site officiel et les sites Web nationaux. Certaines personnes pensent que c'est facultatif et s'en moquent. Cela montre simplement la puissance de React pour répondre aux besoins de projets de différentes tailles. Par exemple, si vous effectuez simplement un simple affichage de données comme ListView et capturez les données, alors une boucle for et {} suffisent. Cependant, il existe un grand nombre de rapports dans le système d'arrière-plan et différents formulaires sont liés entre eux. composants contrôlés, cela ne fonctionnera vraiment pas.

Les composants contrôlés et les composants non contrôlés sont les points d'entrée de React pour traiter les formulaires. Du point de vue de React, l'auteur doit laisser les données contrôler tout, ou simplement comprendre que la génération et la mise à jour de la page doivent exécuter fidèlement les instructions JSX.

Mais les éléments du formulaire ont leurs propres fonctionnalités spéciales. Les utilisateurs peuvent modifier l'affichage de l'interface via la saisie au clavier et la sélection de la souris. Le changement d'interface signifie également que certaines données ont été modifiées. Les plus évidentes sont la valeur de l'entrée, le HTML interne de la zone de texte et la case cochée. Les moins évidentes sont l'index sélectionné et sélectionné. l'option, qui sont modifiées passivement.

 <input value="{this.state.value}"/>
Copier après la connexion

Lorsque le input.value est extrait du state.value du composant, lorsque l'utilisateur effectue une modification d'entrée, puis que JSX redessine à nouveau la vue, le input.value prend-il la nouvelle valeur de l'utilisateur ou l'État ? une nouvelle valeur ? Sur la base de ce désaccord, React a proposé une solution de compromis soutenue par les deux, et le sujet d'aujourd'hui est né.

React estime que value/checked ne peut pas exister seul et doit être utilisé avec onInput/onChange/disabed/readOnly et d'autres propriétés ou événements qui contrôlent value/checked. Ensemble, ils forment un composant contrôlé, contrôlé par JSX. Si l'utilisateur n'écrit pas ces propriétés et événements supplémentaires, le framework y ajoutera certains événements en interne, tels que onClick, onInput et onChange, vous empêchant de saisir ou de sélectionner et vous empêchant de modifier sa valeur. À l'intérieur du framework, il existe une variable tenace, que j'appelle persistValue, qui conserve la dernière valeur qui lui a été attribuée par JSX et ne peut être modifiée que par des événements internes.

On peut donc affirmer que la composante contrôlée est le contrôle de la valeur qui peut être complété par des événements.

Dans les composants contrôlés, persistValue peut toujours être actualisé.

Regardons à nouveau les composants non contrôlés. Puisque value/checked est déjà occupé, React active un autre ensemble d'attributs ignorés en HTML, defaultValue/defaultChecked. On pense généralement qu'ils sont similaires à value/checked, c'est-à-dire que lorsque la valeur n'existe pas, la valeur de defaultValue est considérée comme une valeur.

Nous avons dit plus haut que l'affichage des éléments du formulaire est contrôlé par la persistValue interne, donc defaultXXX synchronisera également persistValue, puis persistValue synchronisera le DOM. Cependant, le point de départ des composants non contrôlés est d'être fidèle aux opérations de l'utilisateur. Si l'utilisateur saisit

input.value = "xxxx"
Copier après la connexion

puis

<input defaultvalue="{this.state.value}"/>
Copier après la connexion

dans le code, cela ne prendra plus effet. et sera toujours xxxx.

Comment fait-il cela, et comment identifier si la modification vient de l'intérieur ou de l'extérieur du cadre ? J'ai parcouru le code source de React, et il s'avère qu'il contient quelque chose appelé valueTracker pour suivre les entrées de l'utilisateur

var tracker = {
  getValue: function () {
   return currentValue;
  },
  setValue: function (value) {
   currentValue = &#39;&#39; + value;
  },
  stopTracking: function () {
   detachTracker(node);
   delete node[valueField];
  }
 };
 return tracker;
}
Copier après la connexion

Cette chose est entrée dans la valeur/vérifiée de l'élément via Object.defineProperty, donc Connaître les opérations d'attribution de valeur de l'utilisateur sur celui-ci.

Mais value/checked sont toujours deux attributs fondamentaux, impliquant trop de mécanismes internes (tels que value et oninput, onchange, les événements de méthode de saisie oncompositionstart,

compositionchange, oncompositionend, onpaste, oncut), afin de modifier la valeur/vérifiée en douceur,

utilise également Object.getOwnPropertyDescriptor. Si je veux être compatible avec IE8, il n’existe pas de gadget aussi avancé. J'adopte une autre approche plus sûre et

modifie simplement defaultValue/defaultChecked avec Object.defineProperty.

J'ajoute d'abord un attribut _uncontrollé à l'élément pour indiquer que j'ai détourné defaultXXX. Ajoutez ensuite un autre commutateur, _observing, dans la méthode set décrivant l'objet (le troisième paramètre de Object.defineProperty). Lorsque la vue est mise à jour à l'intérieur du cadre, cette valeur est fausse. Après la mise à jour, elle est définie sur vrai.

De cette façon, vous saurez si input.defaultValue = "xxx" a été modifié par l'utilisateur ou par le framework.

if (!dom._uncontrolled) {
  dom._uncontrolled = true;
  inputMonitor.observe(dom, name); //重写defaultXXX的setter/getter
}
dom._observing = false;//此时是框架在修改视图,因此需要关闭开关
dom[name] = val;
dom._observing = true;//打开开关,来监听用户的修改行为
Copier après la connexion

L'implémentation d'inputMonitor est la suivante

export var inputMonitor = {};
var rcheck = /checked|radio/;
var describe = {
  set: function(value) {
    var controllProp = rcheck.test(this.type) ? "checked" : "value";
    if (this.type === "textarea") {
      this.innerHTML = value;
    }
    if (!this._observing) {
      if (!this._setValue) {
        //defaultXXX只会同步一次_persistValue
        var parsedValue = (this[controllProp] = value);
        this._persistValue = Array.isArray(value) ? value : parsedValue;
        this._setValue = true;
      }
    } else {
      //如果用户私下改变defaultValue,那么_setValue会被抺掉
      this._setValue = value == null ? false : true;
    }
    this._defaultValue = value;
  },
  get: function() {
    return this._defaultValue;
  },
  configurable: true
};
 
inputMonitor.observe = function(dom, name) {
  try {
    if ("_persistValue" in dom) {
      dom._setValue = true;
    }
    Object.defineProperty(dom, name, describe);
  } catch (e) {}
};
Copier après la connexion

J'ai accidentellement publié un code aussi brûlant le cerveau, ce qui est une mauvaise habitude des codeurs. Cependant, à ce stade, tout le monde comprend que les réactions officielles et anu/qreact contrôlent les entrées des utilisateurs via Object.defineProperty.

Nous pouvons donc comprendre le comportement du code suivant

  var a = ReactDOM.render(<textarea defaultValue="foo" />, container);
  ReactDOM.render(<textarea defaultValue="bar" />, container);
  ReactDOM.render(<textarea defaultValue="noise" />, container);
  expect(a.defaultValue).toBe("noise");
  expect(a.value).toBe("foo");
  expect(a.textContent).toBe("noise");
  expect(a.innerHTML).toBe("noise");
Copier après la connexion

Comme l'utilisateur n'a pas modifié manuellement la valeur par défaut, dom._setValue a toujours été faux/indéfini, donc _persistValue peut toujours être modifié.

Autre exemple :

var renderTextarea = function(component, container) {
  if (!container) {
    container = document.createElement("p");
  }
  const node = ReactDOM.render(component, container);
  node.defaultValue = node.innerHTML.replace(/^\n/, "");
  return node;
};
 
const container = document.createElement("p");
//注意这个方法,用户在renderTextarea中手动改变了defaultValue,_setValue就变成true
const node = renderTextarea(<textarea defaultValue="giraffe" />, container);
 
expect(node.value).toBe("giraffe");
 
// _setValue后,gorilla就不能同步到_persistValue,因此还是giraffe
renderTextarea(<textarea defaultValue="gorilla" />, container);
// expect(node.value).toEqual("giraffe");
 
node.value = "cat";
// 这个又是什么回事了呢,因此非监控属性是在diffProps中批量处理的,在监控属性,则是在更后的方法中处理
// 检测到node.value !== _persistValue,于是重写 _persistValue = node.value,于是输出cat
renderTextarea(<textarea defaultValue="monkey" />, container);
expect(node.value).toEqual("cat");
Copier après la connexion

Classe de texte brut : texte, zone de texte, valeur JSX, toujours convertie en chaîne

type="number" control , la valeur est toujours un numéro. S'il n'est pas renseigné ou est "", il sera converti en "0"

la radio a un effet de liaison Une seule radiocommande du même nom sous le même nœud parent peut être sélectionnée. .

La valeur/valeur par défaut de Select prend en charge les tableaux et n'effectue pas de conversion. Cependant, si l'utilisateur ajoute ou supprime l'élément d'option ci-dessous, sélectionné changera en conséquence.

De plus, la sélection peut être divisée en correspondance floue et correspondance exacte.

//精确匹配
var dom = ReactDOM.render(
  <select value={222}>
    <option value={111}>aaa</option>
    <option value={"222"}>xxx</option>
    <option value={222}>bbb</option>
    <option value={333}>ccc</option>
  </select>,
  container
);
expect(dom.options[2].selected).toBe(true);//选中第三个
Copier après la connexion
//模糊匹配
var dom = ReactDOM.render(
  <select value={222}>
    <option value={111}>aaa</option>
    <option value={"222"}>xxx</option>
    <option value={333}>ccc</option>
  </select>,
  container
);
expect(dom.options[2].selected).toBe(true);//选中第二个
Copier après la connexion

凡此种种,React/anu都是做了大量工作,迷你如preact/react-lite之流则可能遇坑。

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

在vue.js中如何实现数据分发slot

在Vue中有关使用ajax方法有哪些?

通过vue如何引入公共css文件

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal