Was ist der Unterschied zwischen Reaktionskomponente und Reaktionselement? Die Dokumentation erwähnt beide, geht aber nicht ins Detail. Einige Methoden erfordern Komponenten, andere Elemente ...
Antworten:
Hier gibt es drei verwandte Arten von Dingen mit ihren eigenen Namen:
Dies ist etwas überraschend, da Sie, wenn Sie an andere UI-Frameworks gewöhnt sind, erwarten könnten, dass es nur zwei Arten von Dingen gibt, die ungefähr Klassen (wie Widget
) und Instanzen (wie new Widget()
) entsprechen. Dies ist in React nicht der Fall. Komponenteninstanzen sind nicht dasselbe wie Elemente, und es besteht auch keine Eins-zu-Eins-Beziehung zwischen ihnen. Betrachten Sie zur Veranschaulichung diesen Code:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
class MyComponent extends React.Component {
constructor(props) {
super(props);
console.log('This is a component instance:', this);
}
render() {
const another_element = <div>Hello, World!</div>;
console.log('This is also an element:', another_element);
return another_element;
}
}
console.log('This is a component:', MyComponent)
const element = <MyComponent/>;
console.log('This is an element:', element);
ReactDOM.render(
element,
document.getElementById('root')
);
Im obigen Code:
MyComponent
(die Klasse selbst ) ist eine Komponenteelement
ist ein Element. Es ist keine Instanz von MyComponent
; Vielmehr handelt es sich lediglich um eine Beschreibung der zu erstellenden Komponenteninstanz. Es ist ein Objekt mit key
, props
, ref
und type
Eigenschaften. Hier key
und ref
sind null
, props
ist ein leeres Objekt, und type
ist MyComponent
.MyComponent
wird beim element
Rendern erstellt (und protokolliert sich im obigen Beispiel von ihrem Konstruktor) .another_element
ist auch ein Element, und hat key
, ref
, props
und type
Eigenschaften wie element
tut - aber diesmal von dem Wert type
ist die Zeichenfolge "div"
.Die Designgründe, warum React diese drei unterschiedlichen Konzepte hat, werden im Blog-Beitrag React Components, Elements and Instances des React-Teams , den ich zum Lesen empfehle, ausführlich untersucht .
Schließlich ist anzumerken, dass in den offiziellen Dokumenten der Begriff "Komponente" für eine Funktion oder Klasse und "Komponenteninstanz" für eine Instanz streng verwendet wird, andere Quellen diese Terminologie jedoch nicht unbedingt einhalten. Sie sollten erwarten, dass "Komponente" (falsch) als "Komponenteninstanz" verwendet wird, wenn Sie Antworten oder Diskussionen zum Stapelüberlauf auf GitHub lesen.
<Child/>
von ihrer render()
Methode zurückkehrt, wird jedes Mal, wenn sie render()
aufgerufen wird, ein neues Element zurückgegeben, aber eine bereits vorhandene Child
Komponente kann wiederverwendet werden, um dies zu realisieren Element.)
el = <SomeComponent>
und dieses eine Element dann mehrmals in einen großen JSX-Ausdruck einbetten, der von einer render()
Methode zurückgegeben wird (d. H. Do <div>{el}{el}{el}{el}</div>
).
Um die Antwort weiter zu erläutern, verfügt ein Reaktionselement über keine Methoden und nichts über den Prototyp. Das macht sie auch schnell.
"Ein ReactElement ist eine leichte, zustandslose, unveränderliche, virtuelle Darstellung eines DOM-Elements" - Glossar der Reaktionsbegriffe
Eine Reaktionskomponentenfunktion render()
gibt einen DOM-Baum von Reaktionselementen hinter den Kulissen zurück (dies ist übrigens das virtuelle DOM). Es gibt einige komplexe Mapping- und Diff-Logik, aber im Grunde sind diese React-Elemente den DOM-Elementen zugeordnet.
Sie können ein Element auch direkt erstellen, React.createElement(arg)
wobei arg ein HTML-Tag-Name oder eine React Component-Klasse sein kann.
ReactElement
der VDOM selbst ist ... aber ich bin kein großer Experte in diesem Thema, das ist nur eine Vermutung. Nach meinem Verständnis muss noch eine Reaktion Element
auf ein VDOM gerendert werden, die sich dann vom "vorherigen" VDOM unterscheidet. Ich denke user6445533
, die Antwort sagt dasselbe. Recht ? Ich bin kein Experte, aber irgendwie sagt mir der gesunde Menschenverstand, dass dies nach einigem Nachdenken die einzig sinnvolle Interpretation ist ... aber meine Intuition könnte falsch sein.
Ein React-Element ist nur ein einfaches altes JavaScript Object
ohne eigene Methoden. Es hat im Wesentlichen vier Eigenschaften:
type
, eine String
Darstellung eines HTML-Tags oder einer Referenz, die sich auf eine Reaktionskomponente beziehtkey
, a String
, um ein Reaktionselement eindeutig zu identifizierenref
, eine Referenz für den Zugriff auf den zugrunde liegenden DOM-Knoten oder die React Component Instance)props
(Eigenschaften Object
)Ein Reaktionselement ist keine Instanz einer Reaktionskomponente. Es ist nur eine vereinfachte "Beschreibung", wie die type
zu erstellende React Component-Instanz (oder abhängig von einem HTML-Tag) aussehen soll.
Ein Reaktionselement, das eine Reaktionskomponente beschreibt, weiß nicht, auf welchen DOM-Knoten sie schließlich gerendert wird. Diese Zuordnung wird abstrahiert und beim Rendern aufgelöst.
Reaktionselemente können untergeordnete Elemente enthalten und können daher Elementbäume bilden, die den virtuellen DOM-Baum darstellen.
Eine benutzerdefinierte Reaktionskomponente wird entweder durch React.createClass
oder durch Erweitern React.Component
(ES2015) erstellt. Wenn eine Reaktionskomponente instanziiert wird, erwartet sie eine props
Object
und gibt eine Instanz zurück, die als Reaktionskomponenteninstanz bezeichnet wird.
Eine React-Komponente kann den Status enthalten und hat Zugriff auf die React Lifecycle-Methoden. Es muss mindestens eine render
Methode haben, die beim Aufrufen ein Reaktionselement (-tree) zurückgibt. Bitte beachten Sie, dass Sie React Component Instances niemals selbst erstellen, sondern von React für Sie erstellen lassen.
type
Eigenschaften als native HTML-Elemente haben._Es ist wichtig, diese Unterscheidung hier zu treffen, da das Element nicht das ist, was wir auf dem Bildschirm sehen, sondern die Objektdarstellung das ist, was gerendert wird.
createElement
Methode können wir eine Objektdarstellung eines DOM-Knotens (auch bekannt als React-Element) erstellen .
const element = React.createElement(
'div',
{id: 'login-btn'},
'Login'
)
Hier werden createElement
drei Argumente angeführt
Login
)createElement
Aufruf gibt ein Objekt zurück
{
type: 'div',
props: {
children: 'Login',
id: 'login-btn'
}
}
Wenn dies in das DOM gerendert wird (mit ReactDOM.render
), haben wir einen neuen DOM-Knoten, der so aussieht:
<div id='login-btn'>Login</div>
Im Allgemeinen wird React von einem Komponenten-First-Ansatz aus gelehrt. Das Verständnis von Elementen-First ermöglicht jedoch einen reibungslosen Übergang zu Komponenten.
Eine Komponente ist eine Funktion oder eine Klasse, die optional Eingaben akzeptiert und ein React-Element zurückgibt.
Eine Reaktionskomponente ist eine Vorlage. Eine Blaupause. Eine globale Definition. Dies kann entweder eine Funktion oder eine Klasse sein (mit einer Renderfunktion).
Wenn reag eine Klasse oder eine Funktion als erstes Argument sieht, prüft es, welches Element es angesichts der entsprechenden Requisiten rendert, und setzt dies fort, bis keine createElement
Aufrufe mehr vorhanden sind, deren erstes Argument eine Klasse oder eine Funktion ist .
Wenn React ein Element mit einem Funktions- oder Klassentyp sieht, konsultiert es diese Komponente, um zu erfahren, welches Element es angesichts der entsprechenden Requisiten zurückgeben soll.
Am Ende dieses Prozesses verfügt React über eine vollständige Objektdarstellung des DOM-Baums. Dieser gesamte Prozess wird in React als Versöhnung bezeichnet und jedes Mal ausgelöst setState
oder ReactDOM.render
aufgerufen.
Die Klassensyntax ist eine der häufigsten Methoden zum Definieren einer React-Komponente. Es ist zwar ausführlicher als die funktionale Syntax, bietet jedoch mehr Kontrolle in Form von Lifecycle-Hooks.
Erstellen Sie eine Klassenkomponente
// MyComponent.js
import React, { Component } from 'react';
class MyComponent extends Component {
render() {
return (
<div>This is my component.</div>
);
}
}
export default MyComponent;
Verwenden Sie es in jeder anderen Komponente
// MyOtherComponent.js
import React, { Component } from 'react';
import MyComponent from './MyComponent';
class MyOtherComponent extends Component {
render() {
return (
<div>
<div>This is my other component.</div>
<MyComponent />
</div>
);
}
}
export default MyOtherComponent;
Verwenden Sie Requisiten
<MyComponent myProp="This is passed as a prop." />
Auf Requisiten kann mit zugegriffen werden this.props
class MyComponent extends Component {
render() {
const {myProp} = this.props;
return (
<div>{myProp}</div>
);
}
}
Status verwenden
class MyComponent extends Component {
render() {
const {myState} = this.state || {};
const message = `The current state is ${myState}.`;
return (
<div>{message}</div>
);
}
}
Verwenden von Lifecycle-Hooks
class MyComponent extends Component {
// Executes after the component is rendered for the first time
componentDidMount() {
this.setState({myState: 'Florida'});
}
render() {
const {myState} = this.state || {};
const message = `The current state is ${myState}.`;
return (
<div>{message}</div>
);
}
}
Funktionsbasierte Komponenten
Mit createElement
function Button ({ addFriend }) {
return React.createElement(
"button",
{ onClick: addFriend },
"Add Friend"
)
}
function User({ name, addFriend }) {
return React.createElement(
"div",
null,
React.createElement(
"p",
null,
name
),
React.createElement(Button, { addFriend })
)
}
Mit was createElement
kehrt zurück
function Button ({ addFriend }) {
return {
type: 'button',
props: {
onClick: addFriend,
children: 'Add Friend'
}
}
}
function User ({ name, addFriend }) {
return {
type: 'div',
props: {
children: [
{
type: 'p',
props: {
children: name
}
},
{
type: Button,
props: {
addFriend
}
}
]
}
}
}
Hier haben wir eine Button
Komponente, die eine onLogin
Eingabe akzeptiert und ein React-Element zurückgibt.
Button
Komponente erhält eine onLogin
Methode als Eigenschaft.id
Attribut getan haben.React Element
- Es ist ein einfaches Objekt, das einen DOM-Knoten und seine Attribute oder Eigenschaften beschreibt, die Sie sagen können. Es ist ein unveränderliches Beschreibungsobjekt, auf das Sie keine Methoden anwenden können.
Z.B -
<button class="blue"></button>
React Component
- Es ist eine Funktion oder Klasse, die eine Eingabe akzeptiert und ein React-Element zurückgibt. Es muss Verweise auf seine DOM-Knoten und auf die Instanzen der untergeordneten Komponenten beibehalten.
const SignIn = () => (
<div>
<p>Sign In</p>
<button>Continue</button>
<button color='blue'>Cancel</button>
</div>
);
Eine Komponente ist eine Fabrik zum Erstellen von Elementen.
Ein Element ist ein einfaches Objekt, das beschreibt, was auf dem Bildschirm in Bezug auf die DOM-Knoten oder andere Komponenten angezeigt werden soll. Elemente können andere Elemente in ihren Requisiten enthalten. Das Erstellen eines React-Elements ist billig. Sobald ein Element erstellt wurde, wird es nie mehr mutiert. Die Objektdarstellung des React-Elements wäre wie folgt:
const element = React.createElement(
'div',
{id: 'login-btn'},
'Login'
)
Das obige createElement gibt als Objekt wie folgt zurück:
{
type: 'div',
props: {
children: 'Login',
id: 'login-btn'
}
}
Und schließlich wird es mit ReactDOM.render wie folgt in das DOM gerendert.
<div id='login-btn'>Login</div>
Während eine Komponente auf verschiedene Arten deklariert werden kann. Es kann eine Klasse mit einer render () -Methode sein. Alternativ kann es in einfachen Fällen als Funktion definiert werden. In beiden Fällen werden Requisiten als Eingabe verwendet und ein Elementbaum als Ausgabe zurückgegeben. JSX wurde am Ende als createElement transpiliert.
function Button ({ onLogin }) {
return React.createElement(
'div',
{id: 'login-btn', onClick: onLogin},
'Login'
)
}
Hier ist meine Einstellung:
Element
beschreibt, wie das VDOM erstellt wird. Es ist im Grunde eine "eingefrorene" Version des entsprechenden Component Instance
.
Wenn alles wäre, functional component
wäre keine zusätzliche Reaktion erforderlich Element
. Die functional component
Hierarchie könnte den VDOM-Baum direkt erzeugen.
Eine Reaktionshierarchie Component Instance
( tree
) ist eine "Fabrik", und diese Fabrik wird durch die Requisiten parametrisiert, die der Wurzelreaktion zugeführt werden, Component Instance
und durch den gesamten Zustand, der irgendwo im Component Instance
Baum "gespeichert" ist .
Die Reaktion Element
ist also im Grunde ein "abstrakter Syntaxbaum", der in das eigentliche VDOM kompiliert wird.
Warum also nicht das VDOM direkt mit der Reaktion generieren Component Instances
? Das ist hier die eigentliche Frage.
Auf den ersten Blick verstehe ich nicht, warum das nicht möglich wäre. Die Antwort lautet also höchstwahrscheinlich, dass es sich um eine Frage der Leistung handelt.
Die Reaktion Element
ist eine Abstraktionsebene zwischen dem VDOM und dem Component Instance
, warum diese Abstraktion benötigt wird, ist mir nicht ganz klar, höchstwahrscheinlich erlaubt sie Optimierungen. Beispielsweise wird der Element
Baum nicht vollständig gerendert, wenn eine Lebenszyklusmethode auf dem Component Instance
besagt, dass dieser Teilbaum nicht gerendert werden muss.
In diesem Fall "benötigt" die Logik, die diese Optimierung handhabt, diese zusätzliche Indirektionsebene - da die Informationen an einem Ort gespeichert werden müssen, an dem ein Teil des VDOM nicht mit dem neuen VDOM verglichen werden sollte, noch mehr, vielleicht der neue VDOM sollte überhaupt nicht berechnet werden. Die Verwendung einer zusätzlichen Indirektionsebene vereinfacht die Renderlogik und führt zu einer saubereren und wartbareren Implementierung - wie ich mir vorstellen kann.
Dieses Konzept in Haskell heißt " Heben ":
Zum Beispiel sind Monaden in Haskell perfekte Beispiele für solche Aufzüge.
Eine Monade ist eine Art Beschreibung einer Berechnung, die wie folgt als Wert gespeichert werden kann 42
. In ähnlicher Weise reagieren Elements
Elemente einer Beschreibung, wie das "neue" VDOM berechnet wird. Wenn jemand es berechnen will.
Dieser Vortrag beschreibt dieses Konzept einer "zusätzlichen" Indirektion mit einigen einfachen Beispielen :
Mit anderen Worten: Vorzeitige Optimierung ist die Wurzel allen Übels.
Oder: Grundsatz der Softwareentwicklung
Der Grundsatz der Softwareentwicklung (FTSE) ist ein Begriff, der von Andrew Koenig stammt, um eine Bemerkung von Butler Lampson 1 zu beschreiben, die dem verstorbenen David J. Wheeler zugeschrieben wird: 2
Wir können jedes Problem lösen, indem wir eine zusätzliche Indirektionsebene einführen.
Nach meinem Verständnis sind Reagieren Elements
ein Implementierungsdetail, um die Komplexität angemessen zu handhaben und eine gewisse Optimierung (Leistung) zu ermöglichen. Ich verstehe nicht, warum man diese zusätzliche Indirektion nicht loswerden konnte - im Prinzip - reagieren würde immer noch "genauso gut" funktionieren - aber es könnte sehr langsam sein, die Implementierung und Wartung der reaktionsfähigen "Engine" selbst wäre wahrscheinlich ein Albtraum .
Bitte korrigieren Sie mich, wenn mir hier etwas fehlt.
Zitieren eines WICHTIGEN Teils der Antwort von user6445533:
type
, eine Zeichenfolge, die ein HTML-Tag oder eine Referenz darstellt, die auf eine Reaktionskomponente verweist
DAS IST DER SCHLÜSSEL ^^^^
Element IST NICHT VDOM.
A React Element
ist das, was Sie als grundlegendes HTML-Element (genauer gesagt dom) betrachten würden. Es ist nur eine Möglichkeit, Elemente zu erstellen, ohne das umstrittene jsx-Format zu verwenden.
A React Component
ist das, was Sie als Objekt betrachten können. Es hat seine Methoden, unterstützt React lifecycles
und ist im Allgemeinen nicht wiederverwendbar (zumindest noch keine Wiederverwendung gefunden, willkommen zu Beispielen). Es muss unbedingt eine Renderfunktion haben.
A React Class
nennt man eine Klasse. Funktionalität weise React Class
und React Component
sind gleich. Nur die Syntax ist die eigentliche Änderung, auf der React Component
basiert ES6 syntax
. Eine weitere wichtige Änderung ist, dass die Standardbindung von Funktionen an diese nicht mehr unterstützt wird, es sei denn, Sie verwenden Pfeilfunktionen. Mixins
werden ab sofort auch nicht mehr unterstützt ES6
.
Elemente sind Thunks.
Mit React können Sie Benutzeroberflächen als reine Funktionen definieren, die im Anwendungsstatus definiert sind. Dies könnte implementiert werden, indem die gesamte Benutzeroberfläche bei jeder Statusänderung berechnet wird. Dies wäre jedoch teuer. Elemente sind rechnerische Beschreibungen (Thunks). Wenn sie sich nicht ändern und Sie PureComponent
s verwenden, wird React diesen Teilbaum nicht neu berechnen.