Heim  >  Artikel  >  Web-Frontend  >  Detaillierte Erläuterung der von React kontrollierten und unkontrollierten Komponenten

Detaillierte Erläuterung der von React kontrollierten und unkontrollierten Komponenten

小云云
小云云Original
2017-12-18 16:21:533007Durchsuche

In diesem Artikel werden hauptsächlich die kontrollierten und unkontrollierten Komponenten von React erläutert. Auf der offiziellen Website und auf inländischen Websites gibt es nicht viele Informationen Es ist ihnen egal. Dies zeigt nur die Leistungsfähigkeit von React, die Anforderungen von Projekten unterschiedlicher Größe zu erfüllen. Wenn Sie beispielsweise nur eine einfache Datenanzeige wie ListView durchführen und die Daten erfassen, dann reichen eine for-Schleife und {} aus. Allerdings gibt es im Hintergrundsystem eine große Anzahl von Berichten und verschiedene Formulare sind miteinander verknüpft. Ohne geregelte Komponenten geht es wirklich nicht.

Kontrollierte Komponenten und unkontrollierte Komponenten sind die Einstiegspunkte für React, um Formulare zu verarbeiten. Aus der Sicht von React muss der Autor die Daten alles kontrollieren lassen oder einfach verstehen, dass die Generierung und Aktualisierung der Seite die JSX-Anweisungen getreu ausführen muss.

Formularelemente haben jedoch ihre eigenen Besonderheiten. Benutzer können die Anzeige der Benutzeroberfläche durch Tastatureingabe und Mausauswahl ändern. Die Änderung in der Schnittstelle bedeutet auch, dass einige Daten geändert wurden. Die offensichtlicheren sind der Wert der Eingabe, der innerHTML des Textbereichs, die aktivierten von Radio/Kontrollkästchen, nicht so Die offensichtlichsten sind die Optionen selected und selectedIndex, die passiv geändert werden.

<input value={this.state.value} />

Wenn der input.value vom state.value der Komponente übernommen wird, wenn der Benutzer eine Eingabeänderung vornimmt und JSX dann die Ansicht erneut zeichnet, übernimmt der input.value den neuen Wert des Benutzers oder? der Staat? neuer Wert? Basierend auf dieser Meinungsverschiedenheit lieferte React eine Kompromisslösung, die von beiden unterstützt wurde, und das heutige Thema war geboren.

React glaubt, dass value/checked nicht alleine existieren kann und zusammen mit onInput/onChange/disabed/readOnly und anderen Eigenschaften oder Ereignissen verwendet werden muss, die value/checked steuern. Zusammen bilden sie eine kontrollierte Komponente, die von JSX gesteuert wird. Wenn der Benutzer diese zusätzlichen Eigenschaften und Ereignisse nicht schreibt, fügt das Framework intern einige Ereignisse hinzu, z. B. onClick, onInput und onChange, wodurch Sie daran gehindert werden, Eingaben oder Auswahlen vorzunehmen und den Wert zu ändern. Innerhalb des Frameworks gibt es eine hartnäckige Variable, die ich persistValue nenne, die den ihr zuletzt von JSX zugewiesenen Wert beibehält und nur durch interne Ereignisse geändert werden kann.

Daher können wir behaupten, dass die kontrollierte Komponente die Wertkontrolle ist, die durch das Ereignis abgeschlossen werden kann.

In kontrollierten Komponenten kann persistValue jederzeit aktualisiert werden.

Sehen wir uns noch einmal die unkontrollierten Komponenten an. Da value/checked bereits belegt ist, aktiviert React einen weiteren Satz ignorierter Attribute in HTML, defaultValue/defaultChecked. Es wird allgemein angenommen, dass sie value/checked ähneln, d. h. wenn kein Wert vorhanden ist, wird der Wert von defaultValue als Wert betrachtet.

Wir haben oben gesagt, dass die Anzeige von Formularelementen durch den internen persistValue gesteuert wird, sodass defaultXXX auch persistValue synchronisiert und persistValue dann das DOM synchronisiert. Der Ausgangspunkt unkontrollierter Komponenten besteht jedoch darin, den Benutzeroperationen treu zu bleiben. Wenn der Benutzer

input.value = "xxxx"

und dann

<input defaultValue={this.state.value} />

in den Code eingibt, wird dies nicht mehr wirksam und wird immer xxxx sein.

Wie geht das und wie erkennt man, ob die Änderung von innerhalb oder außerhalb des Frameworks kommt? Ich habe den Quellcode von React durchgesehen und es stellte sich heraus, dass es etwas namens valueTracker gibt, um Benutzereingaben zu verfolgen

var tracker = {
    getValue: function () {
      return currentValue;
    },
    setValue: function (value) {
      currentValue = '' + value;
    },
    stopTracking: function () {
      detachTracker(node);
      delete node[valueField];
    }
  };
  return tracker;
}

Dieses Ding wird über Object.defineProperty in den Wert des Elements eingegeben/überprüft, also Es kennt die Wertzuweisungsoperationen des Benutzers darauf.

Aber value/checked sind immer noch zwei sehr zentrale Attribute, die zu viele interne Mechanismen beinhalten (wie value und oninput, onchange, Eingabemethodenereignisse oncompositionstart,
compositionchange, oncompositionend, onpaste, oncut), der Reihe nach Um den Wert/die Überprüfung reibungslos zu ändern, muss
auch Object.getOwnPropertyDescriptor verwendet werden. Wenn ich mit IE8 kompatibel sein möchte, gibt es kein so fortschrittliches Gadget. Ich wähle einen anderen, sichereren Ansatz:
ändere einfach defaultValue/defaultChecked mit Object.defineProperty.

Zuerst füge ich dem Element ein _uncontrolled-Attribut hinzu, um anzuzeigen, dass ich defaultXXX gekapert habe. Fügen Sie dann einen weiteren Schalter, Object.defineProperty的第三个参数, zur Set-Methode des Beschreibungsobjekts (_observing) hinzu. Wenn die Ansicht innerhalb des Frames aktualisiert wird, ist dieser Wert „false“. Nach der Aktualisierung wird er auf „true“ gesetzt.

Auf diese Weise wissen Sie, ob input.defaultValue = "xxx" vom Benutzer oder vom Framework geändert wurde.

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

Die Implementierung von inputMonitor ist wie folgt

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

Ich habe versehentlich solchen Code gepostet, der den Kopf verbrennt, was eine schlechte Angewohnheit von Programmierern ist. An diesem Punkt versteht jedoch jeder, dass sowohl offizielle Reaktionen als auch Anu/Qreact Benutzereingaben über Object.defineProperty steuern.

Damit wir das Verhalten des folgenden Codes verstehen können

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

Da der Benutzer den Standardwert nicht manuell geändert hat, war dom._setValue immer falsch/undefiniert , also _persistValue Kann jederzeit geändert werden.

Ein weiteres Beispiel:

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

Natürlich gibt es viele Arten von Formularelementen, und jedes Formularelement hat auch sein Standardverhalten.

纯文本类:text, textarea, JSX的值,总是往字符串转换
type="number"的控制,值总是为数字,不填或为“”则转换为“0”
radio有联动效果,同一父节点下的相同name的radio控制只能选择一个。
select的value/defaultValue支持数组,不做转换,但用户对底下的option元素做增删操作,selected会跟着变动。

此外select还有模糊匹配与精确匹配之分。

//精确匹配
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);//选中第三个
//模糊匹配
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);//选中第二个

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

相关推荐:

react如何实现菜单权限控制?

React 内部机制探秘

React中组件的写法有哪些


Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung der von React kontrollierten und unkontrollierten Komponenten. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn