Dieser Artikel hilft Ihnen, den Quellcode von PReact10.5.13 zu verstehen

Dieser Artikel hilft Ihnen, den Quellcode von PReact10.5.13 zu verstehen

Ich habe den React-Quellcode mehrmals gelesen, bin aber nicht jedes Mal dabei geblieben. Ich habe einfach den PReact-Teil gelernt. Es gibt viele Erklärungen des Quellcodes im Internet, aber sie sind im Grunde veraltet, also werde ich das selbst klären.

render.js-Teil

importiere { EMPTY_OBJ, EMPTY_ARR } aus './constants';
importiere { commitRoot, diff } von './diff/index';
importiere { createElement, Fragment } aus './create-element';
Optionen aus „./options“ importieren;

/**
 * Rendern Sie einen virtuellen Preact-Knoten in ein DOM-Element
 * @param {import('./internal').ComponentChild} vnode Der zu rendernde virtuelle Knoten
 * @param {import('./internal').PreactElement} parentDom Das zu
 * rendern in
 * @param {import('./internal').PreactElement | object} [replaceNode] Optional: Versuch der Wiederverwendung eines
 * vorhandener DOM-Baum mit der Wurzel „replaceNode“
 */
Exportfunktion rendern (vnode, parentDom, replaceNode) {
 wenn (Optionen._root) Optionen._root (vnode, parentDom);

 // Wir missbrauchen den Parameter „replaceNode“ in „hydrate()“, um zu signalisieren, ob wir uns in
 // Hydratationsmodus oder nicht durch Übergeben der Funktion `hydrate` anstelle eines DOM
 // Element..
 let isHydrating = Typ von replaceNode === 'Funktion';

 // Um ​​den mehrmaligen Aufruf von `render()` auf derselben
 // DOM-Knoten, wir müssen einen Verweis auf den vorherigen Baum erhalten. Wir tun
 // dies durch die Zuweisung einer neuen `_children`-Eigenschaft zu DOM-Knoten, die zeigt
 // zum letzten gerenderten Baum. Standardmäßig ist diese Eigenschaft nicht vorhanden, was
 // bedeutet, dass wir zum ersten Mal einen neuen Baum mounten.
  // Um ​​mehrere Aufrufe der Renderfunktion auf einem DOM-Knoten zu unterstützen, müssen Sie auf dem DOM-Knoten ein Rendering hinzufügen, damit der virtuelle DOM-Baum auf das letzte Rendering verweist.
  // Diese Eigenschaft zeigt standardmäßig auf null, was bedeutet, dass wir zum ersten Mal einen neuen Baum ausstatten // Am Anfang ist oldVNode also null (unabhängig vom Wert von isHydrating), aber wenn Sie render auf diesem Knoten wiederholt aufrufen, hat oldVNode einen Wert let oldVNode = isHydrating
  ? Null
  : (Ersatzknoten und Ersetzungsknoten._Kinder) || parentDom._Kinder;

 // vnode mit Fragment umschließen und vnode an replaceNode und parentDoms _children zuweisen = (
  (!isHydrating && replaceNode) ||
  ElternDom
 )._children = createElement(Fragment, null, [vnode]);

 // Liste der Effekte, die nach dem Diffing aufgerufen werden müssen.
  // Wird zum Platzieren von Komponenten verwendet, die nach dem Diff verschiedene Lebenszyklusverarbeitungen durchlaufen müssen, wie z. B. cdm und cdu; componentWillUnmount wird in der Unmount-Funktion von diffChildren ausgeführt und nicht ausgeführt, wenn commitRoot verwendet wird. let commitQueue = [];
 Unterschied(
  parentDom, // Dies verwendet die _children-Eigenschaft von parentDom, um auf [vnode] zu verweisen // Bestimmen Sie den neuen vnode-Baum und speichern Sie ihn im DOM-Element auf
  // unsere benutzerdefinierte „_children“-Eigenschaft.
  vKnoten,
  oldVNode || EMPTY_OBJ, // Alter Baum EMPTY_OBJ,
  parentDom.ownerSVGElement !== undefiniert,
    // excessDomChildren, dieser Parameter wird für die Dom-Wiederverwendung verwendet! isHydrating && replaceNode
   ? [Knoten ersetzen]
   : alterVNode
   ? Null
   : parentDom.firstChild // Wenn parentDom untergeordnete Knoten hat, wird der gesamte untergeordnete Knoten als wiederzuverwendender Knoten verwendet? EMPTY_ARR.slice.call(parentDom.childNodes)
   : null,
  CommitQueue,
    // oldDom, wird verwendet, um die Einfügeposition in nachfolgenden Methoden zu markieren!isHydrating && replaceNode
   ? Knoten ersetzen
   : alterVNode
   ? alterVNode._dom
   : parentDom.erstesKind,
  isthydratisierend
 );

 // Lösche alle Effekte in der Warteschlange
  // Rufen Sie die Methode commitRoot(commitQueue, vnode) in allen nodes_renderCallbacks in commitQueue auf;
}

/**
 * Aktualisieren Sie ein vorhandenes DOM-Element mit Daten von einem virtuellen Preact-Knoten
 * @param {import('./internal').ComponentChild} vnode Der zu rendernde virtuelle Knoten
 * @param {import('./internal').PreactElement} parentDom Das zu
 * aktualisieren
 */
Exportfunktion hydratisieren(vnode, parentDom) {
 rendern (vnode, parentDom, hydratisieren);
}

create-context.js-Teil

Verwendung des Kontexts:

Es gibt ein Wertattribut in den Eigenschaften des Anbieters

Holen Sie sich den Wert direkt im Verbraucher

importiere { createContext, h, render } von „preact“;

const FontContext = createContext(20);

Funktion Kind() {
 gibt <FontContext.Consumer> zurück
 {fontSize=><div Stil={{fontSize:fontSize}}>Kind</div>}
 </FontContext.Consumer>
}
Funktion App(){
 return <Untergeordnetes Element/>
}
machen(
 <FontContext.Provider-Wert={26}>
 <App/>
 </FontContext.Provider>,
 document.getElementById('app')
);

Schauen Sie sich den Quellcode an:

importiere { enqueueRender } von './Komponente';

Exportiere lass i = 0;

Exportfunktion createContext(Standardwert, Kontext-ID) {
 contextId = '__cC' + i++; // Eine eindeutige ID generieren

 const Kontext = {
  _id: Kontext-ID,
  _defaultValue: Standardwert,
  /** @type {import('./internal').Funktionskomponente} */
  Verbraucher(Eigenschaften, Kontextwert) {
   // gibt Eigenschaften.Kinder zurück(
   // Kontext[Kontext-ID] ? Kontext[Kontext-ID].props.value : Standardwert
   // );
   gibt props.children(Kontextwert) zurück;
  },
  /** @type {import('./internal').Funktionskomponente} */
  Anbieter(Eigenschaften) {
   if (!this.getChildContext) { // Beim ersten Aufruf einige Initialisierungsvorgänge ausführen let subs = [];
    lass ctx = {};
    ctx[Kontext-ID] = dies;
       
       // Wenn beim Diff-Vorgang festgestellt wird, dass sich eine Komponente im Consumer befindet, wird „sub“ zum Abonnieren aufgerufen.
       // Gleichzeitig tragen alle nachfolgenden Diffs dieses Knotens diesen Kontext. Der Aufruf der Untermethode zum Aufrufen des // Kontexts hat hierarchische Priorität und die Komponente wird zuerst dem nächstgelegenen Kontext hinzugefügt. this.getChildContext = () => ctx; 

    dies.shouldComponentUpdate = Funktion(_props) {
     wenn (dieser.props.value !== _props.value) {
      // Ich denke, die erzwungene Wertweitergabe war hier nur erforderlich, wenn „options.debounceRendering“ umgangen wurde:
      // https://github.com/preactjs/preact/commit/4d339fb803bea09e9f198abf38ca1bf8ea4b7771#diff-54682ce380935a717e41b8bfc54737f6R358
      // In diesen Fällen rendern wir jedoch alle Knoten doppelt, selbst wenn der Wert korrigiert ist.
      // Es wäre vielleicht besser, den Leuten einfach zu sagen, dass sie den Force-Sync-Modus nicht verwenden sollen.
      // Derzeit überschreibt die Verwendung von „useContext()“ in einer Klassenkomponente deren „this.context“-Wert.
      // subs.some(c => {
      // c.Kontext = _props.Wert;
      // enqueueRender(c);
      // });

      // subs.some(c => {
      // c.context[Kontext-ID] = _props.value;
      // enqueueRender(c);
      // });
            // enqueueRender wird schließlich die Funktion renderComponent aufrufen, um Vorgänge wie diff, commitRoot, updateParentDomPointers usw. auszuführen. subs.some(enqueueRender);
     }
    };

    dies.sub = c => {
     subs.push(c);// Geben Sie das Abonnement-Array ein,
     lass alt = c.componentWillUnmount;
     c.componentWillUnmount = () => { // componentWillUnmount überschreiben
      subsplice(subs.indexOf(c), 1);
      wenn (alt) alt.call(c);
     };
    };
   }

   gib Requisiten.Kinder zurück;
  }
 };

 // Devtools benötigt Zugriff auf das Kontextobjekt, wenn es
 // trifft auf einen Provider. Dies ist notwendig, um
 // stattdessen `displayName` auf dem Kontextobjekt festlegen
 // von auf der Komponente selbst. Siehe:
 // https://reactjs.org/docs/context.html#contextdisplayname
 // createContext gibt letztendlich ein Kontextobjekt mit zwei Funktionen zurück, Provider und Consumer. // Gleichzeitig verweisen sowohl die contextType-Eigenschaft der Consumer-Funktion als auch die _contextRef-Eigenschaft der Provider-Funktion auf den Kontext.
 Rückgabe (Kontext.Provider._ContextRef = Kontext.Consumer.ContextType = Kontext);
}

Daher wird für die Providerkomponente beim Rendern ermittelt, ob eine getChildContext-Methode vorhanden ist. Wenn ja, wird sie aufgerufen, um den globalContext abzurufen und weiterzugeben.

wenn (c.getChildContext != null) {
    globalContext = zuweisen(zuweisen({}, globalContext), c.getChildContext());
   }

   wenn (!isNew && c.getSnapshotBeforeUpdate != null) {
    Schnappschuss = c.getSnapshotBeforeUpdate(oldProps, oldState);
   }

   let istTopLevelFragment =
    tmp != null und tmp.Typ === Fragment und tmp.Schlüssel == null;
   let renderResult = isTopLevelFragment? tmp.props.children: tmp;

   diffKinder(
    ElternDom,
    Array.isArray(renderResult) ? renderResult : [renderResult],
    neuer VNode,
    alterVNode,
    globalerKontext,
    istSvg,
    ÜberschussDomKinder,
    CommitQueue,
    alterDom,
    isthydratisierend
   );

Wenn das Rendering auf Consumer trifft, also auf das ContextType-Attribut, wird zuerst der Provider aus dem Context abgerufen und dann der Wert der Props des Providers als Kontextinformation, die die Komponente abrufen möchte. Gleichzeitig wird die Submethode des Anbieters zum Abonnieren aufgerufen. Wenn sich der Wert im shouldComponentUpdate des Anbieters ändert, geben alle Abonnenten die Funktion enqueueRender ein.

Daher verweist im Quellcode jeder Schlüssel des globalContext-Objekts auf einen Context.Provider; componentContext stellt die vom Consumer übergebenen Kontextinformationen dar, in denen sich die Komponente befindet, dh den Wert der Eigenschaften des gepaarten Providers;

Gleichzeitig verwendet die Methode shouldComponentUpdate des Providers ·this.props.value !== _props.value·. Woher kommt also this.props? Es gibt keine zugehörige Eigenschaft im Provider.

Das Wichtigste ist der folgende Ort. Wenn festgestellt wird, dass keine Rendermethode vorhanden ist, wird Compoent zum Instanziieren eines Objekts verwendet, die Rendermethode wird auf doRender gesetzt, der Konstruktor zeigt auf newType (die aktuelle Funktion), und die Methode this.constructor wird in doRender aufgerufen

// Instanziieren Sie die neue Komponente
    wenn ('Prototyp' in neuerTyp && neuerTyp.Prototyp.Render) {
     // @ts-ignore Die obige Prüfung bestätigt, dass newType erstellt werden soll
     newVNode._component = c = neuer neuerTyp(newProps, componentContext); // eslint-disable-line new-cap
    } anders {
     // @ts-ignore Vertrauen Sie mir, Component implementiert die Schnittstelle, die wir wollen
     newVNode._component = c = neue Komponente (newProps, Komponentenkontext);
     c.Konstruktor = neuerTyp;
     c.render = doRender;
    }
/** Die `.render()`-Methode für eine PFC-Backing-Instanz. */
Funktion doRender(Eigenschaften, Status, Kontext) {
 gib dies zurück.Konstruktor(Requisiten, Kontext);
}

Diff-Teil

Der Diff-Teil ist komplizierter, also habe ich ein Gesamtbild organisiert

Ich muss wirklich bemängeln, dass der Editor von Blog Garden zu viele Bugs hat, insbesondere bei der Verwendung auf dem Mac. Beispielsweise kann der Code beim zweiten Upload nicht übermittelt werden; Zuweisung und Einfügen können nicht verwendet werden. . .

Nur Gefühle halten mich dazu an, hier auf dem Laufenden zu bleiben

Dies ist das Ende dieses Artikels, der Ihnen dabei helfen soll, den PReact10.5.13-Quellcode zu verstehen. Weitere relevante Inhalte zum PReact10.5.13-Quellcode finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, dass jeder 123WORDPRESS.COM in Zukunft unterstützen wird!

Das könnte Sie auch interessieren:
  • Wie React-Komponenten ihre untergeordneten Komponenten stärken
  • Anwendungsbeispiele für React Hooks
  • Tiefgreifendes Verständnis der Kernprinzipien von React Native (Bridge of React Native)
  • React+Koa-Beispiel zur Implementierung des Datei-Uploads
  • Beispielcode für die Entwicklung einer H5-Formularseite basierend auf React-Hooks und der Konfiguration der Zarm-Komponentenbibliothek
  • Das Umschalten zwischen React-Antd-Tabs führt zu wiederholter Aktualisierung von Unterkomponenten
  • ReactJs-Grundlagen-Tutorial - Essential Edition
  • Eine kurze Erläuterung verschiedener Möglichkeiten zum Übergeben von Parametern beim React-Routing
  • Detaillierte Verwendung von React.Children

<<:  Detaillierte Erläuterung der Konfigurationsmethode für den Lastenausgleich von Apache + Tomcat7 unter Windows

>>:  So ändern Sie das vergessene Passwort bei der Installation von MySQL auf dem Mac

Artikel empfehlen

Zusammenfassung des fragmentierten Wissens zum Docker-Management

Inhaltsverzeichnis 1. Übersicht 2. Anwendungsbeis...

So erstellen Sie ein React-Projekt mit Vite

Inhaltsverzeichnis Vorwort Erstellen Sie ein Vite...

So ändern Sie die Zeit in der virtuellen CentOS-Maschine

Das obere Bild zeigt die Systemzeit und das unter...

Detaillierte Analyse der Verwendungs- und Anwendungsszenarien von Slots in Vue

Was sind Slots? Wir wissen, dass in Vue nichts in...

So verwenden Sie VUE, um die Ali Iconfont-Bibliothek online aufzurufen

Vorwort Vor vielen Jahren war ich ein Neuling auf...

Detaillierte Erklärung der berechneten Eigenschaften von Vue

1. Was ist ein berechnetes Attribut? Einfach ausg...

Beispielanalyse zur Metadatenextraktion von MySQL und Oracle

Inhaltsverzeichnis Vorwort Was sind Metadaten? Ad...

Detaillierte Erläuterung der Anwendungsbeispiele für Vue-Router 4

Inhaltsverzeichnis 1. Installieren und erstellen ...

HTML-Kopfstruktur

Im Folgenden werden die häufig verwendete Kopfstr...

Spezifische Verwendung interner temporärer MySQL-Tabellen

Inhaltsverzeichnis UNION Tabelleninitialisierung ...