Dieses Tutorial ist das zweite einer dreiteiligen Serie über React von Brad Westfall. Diese Serie dreht sich darum, über grundlegende React-Fähigkeiten hinauszugehen und größere Dinge zu bauen, wie z. B. ganze Single Page Applications (SPAs). Dieser Artikel knüpft dort an, wo der letzte Artikel über React Router aufgehört hat.
Artikelserie
- React Router
- Container-Komponenten (Sie sind hier!)
- Redux
Im ersten Artikel haben wir Routen und Ansichten erstellt. In diesem Tutorial werden wir ein neues Konzept untersuchen, bei dem Komponenten keine Ansichten erstellen, sondern die ermöglichen, die es tun. Es gibt Code zum Mitverfolgen auf GitHub, wenn Sie direkt in den Code eintauchen möchten.
Wir werden auch Daten in unsere Anwendung einführen. Wenn Sie mit irgendeiner Art von Komponenten-Design oder MVC-Mustern vertraut sind, wissen Sie wahrscheinlich, dass es im Allgemeinen als schlechte Praxis gilt, Ihre Ansichten mit dem Anwendungsverhalten zu vermischen. Anders ausgedrückt: Während Ansichten Daten erhalten müssen, um sie zu rendern, sollten sie nicht wissen, woher die Daten stammen, wie sie sich ändern oder wie sie erstellt werden.
Daten mit Ajax abrufen
Als Beispiel für eine schlechte Praxis erweitern wir unsere UserList-Komponente aus dem vorherigen Tutorial, um das eigene Abrufen von Daten zu handhaben
// This is an example of tightly coupled view and data which we do not recommend
var UserList = React.createClass({
getInitialState: function() {
return {
users: []
}
},
componentDidMount: function() {
var _this = this;
$.get('/path/to/user-api').then(function(response) {
_this.setState({users: response})
});
},
render: function() {
return (
<ul className="user-list">
{this.state.users.map(function(user) {
return (
<li key={user.id}>
<Link to="{'/users/' + user.id}">{user.name}</Link>
</li>
);
})}
</ul>
);
}
});
Wenn Sie eine detailliertere/anfängerfreundlichere Erklärung benötigen, was diese Komponente tut, siehe diese Erklärung.
Warum ist das Beispiel weniger als ideal? Erstens haben wir die Regel gebrochen, "Verhalten" mit "wie die Ansicht gerendert wird" zu vermischen – die beiden Dinge, die getrennt bleiben sollten.
Um es klarzustellen: Es ist nichts falsch daran, getInitialState zur Initialisierung des Komponentenstatus zu verwenden, und es ist nichts falsch daran, einen Ajax-Aufruf von componentDidMount auszuführen (obwohl wir den eigentlichen Aufruf wahrscheinlich in andere Funktionen auslagern sollten). Das Problem ist, dass wir diese Dinge *gemeinsam* in derselben Komponente tun, in der die Ansicht gespeichert ist. Diese enge Kopplung macht die Anwendung starrer und WET. Was ist, wenn Sie eine Benutzerliste auch woanders abrufen müssen? Die Aktion des Abrufens von Benutzern ist an diese Ansicht gebunden, daher ist sie nicht wiederverwendbar.
Das zweite Problem ist, dass wir jQuery für den Ajax-Aufruf verwenden. Sicher, jQuery hat viele nette Funktionen, aber die meisten davon befassen sich mit DOM-Rendering und React hat seinen eigenen Weg, dies zu tun. Was jQuerys Nicht-DOM-Funktionen wie Ajax betrifft, werden Sie wahrscheinlich viele Alternativen finden, die auf eine einzelne Funktion fokussierter sind.
Eine dieser Alternativen ist Axios, ein Promise-basiertes Ajax-Tool, das (in Bezug auf die API) sehr ähnlich zu jQuerys Promise-basierten Ajax-Funktionen ist. Wie ähnlich sind sie?
// jQuery
$.get('/path/to/user-api').then(function(response) { ... });
// Axios
axios.get('/path/to/user-api').then(function(response) { ... });
Für die restlichen Beispiele verwenden wir weiterhin Axios. Andere ähnliche Tools sind got, fetch und SuperAgent.
Props und State
Bevor wir uns mit Container- und Presentational Components befassen, müssen wir etwas über Props und State klären.
Props und State sind in gewisser Weise verwandt, da sie beide Daten für React-Komponenten "modellieren". Beide können von übergeordneten zu untergeordneten Komponenten weitergegeben werden. Die Props und der State einer übergeordneten Komponente werden jedoch für ihre untergeordnete Komponente einfach zu Props.
Nehmen wir zum Beispiel an, ComponentA übergibt einige seiner Props und seines States an seine untergeordnete Komponente, ComponentB. Die render-Methode von ComponentA könnte so aussehen
// ComponentA
render: function() {
return <ComponentB foo={this.state.foo} bar={this.props.bar} />
}
Obwohl foo "State" in der übergeordneten Komponente ist, wird es zu einem "Prop" in der untergeordneten Komponente ComponentB. Das Attribut für bar wird ebenfalls zu einem Prop in der untergeordneten Komponente, da alle von der übergeordneten zur untergeordneten Komponente übergebenen Daten in der untergeordneten Komponente zu Props werden. Dieses Beispiel zeigt, wie eine Methode von ComponentB als Props auf foo und bar zugreifen kann
// ComponentB
componentDidMount: function() {
console.log(this.props.foo);
console.log(this.props.bar);
}
Im Beispiel *Fetching Data with Ajax* werden Daten, die von Ajax empfangen werden, als State der Komponente gesetzt. Das Beispiel hat keine untergeordneten Komponenten, aber Sie können sich vorstellen, dass, wenn es welche hätte, der State als Props von übergeordnet zu untergeordnet "fließen" würde.
Um den State besser zu verstehen, siehe die React-Dokumentation. Von nun an wird dieses Tutorial die sich im Laufe der Zeit ändernden Daten als "State" bezeichnen.
Zeit zum Aufteilen
Im Beispiel *Fetching Data with Ajax* haben wir ein Problem geschaffen. Unsere UserList-Komponente funktioniert, aber sie versucht, zu viele Dinge zu tun. Um das Problem zu lösen, zerlegen wir die UserList in zwei Komponenten, die jeweils eine andere Rolle erfüllen. Die beiden Komponententypen werden konzeptionell als Container-Komponenten und Presentational-Komponenten, auch bekannt als "smarte" und "dumme" Komponenten, bezeichnet.
Kurz gesagt: Container-Komponenten beziehen die Daten und befassen sich mit dem State. Der State wird dann an Presentational-Komponenten als Props übergeben und dann in Ansichten gerendert.
Die Begriffe "smarte" vs. "dumme" Komponenten verschwinden in der Community. Ich beziehe mich nur auf sie, falls Sie in älteren Artikeln darüber lesen, damit Sie wissen, dass sie dasselbe Konzept wie Container vs. Presentational sind.
Presentational-Komponenten
Sie wissen es vielleicht nicht, aber Sie haben in dieser Tutorial-Serie bereits Presentational Components gesehen. Stellen Sie sich einfach vor, wie die UserList-Komponente aussah, bevor sie ihren eigenen State verwaltete
var UserList = React.createClass({
render: function() {
return (
<ul className="user-list">
{this.props.users.map(function(user) {
return (
<li key={user.id}>
<Link to="{'/users/' + user.id}">{user.name}</Link>
</li>
);
})}
</ul>
);
}
});
Es ist nicht *genau* dasselbe wie vorher, aber es *ist* eine Presentational Component. Der große Unterschied zwischen ihr und dem Original ist, dass diese über Benutzerdaten iteriert, um Listenelemente zu erstellen, und die Benutzerdaten über Props erhält.
Presentational Components sind "dumm" in dem Sinne, dass sie keine Ahnung haben, wie die erhaltenen Props zustande gekommen sind. Sie haben keine Ahnung vom State.
Presentational Components sollten die Prop-Daten niemals selbst ändern. Tatsächlich sollte jede Komponente, die Props erhält, diese Daten als unveränderlich und im Besitz der übergeordneten Komponente betrachten. Während die Presentational Component die Bedeutung der Daten im Prop nicht ändern sollte, kann sie die Daten für die Ansicht formatieren (z. B. einen Unix-Zeitstempel in etwas menschlich Lesbareres umwandeln).
In React werden Ereignisse direkt an die Ansicht mit Attributen wie onClick angehängt. Man könnte sich jedoch fragen, wie Ereignisse funktionieren, da Presentational Components Props nicht ändern sollen. Dafür haben wir unten einen ganzen Abschnitt über Ereignisse.
Iterationen
Beim Erstellen von DOM-Knoten in einer Schleife muss das key-Attribut eindeutig sein (relativ zu seinen Geschwisterelementen). Beachten Sie, dass dies nur für den obersten DOM-Knoten gilt – in diesem Fall das <li>.
Auch wenn das verschachtelte return für Sie seltsam aussieht, sollten Sie einen anderen Ansatz in Betracht ziehen, der dasselbe tut, indem er die Erstellung eines Listenelements in eine eigene Funktion aufteilt
var UserList = React.createClass({
render: function() {
return (
<ul className="user-list">
{this.props.users.map(this.createListItem)}
</ul>
);
},
createListItem: function(user) {
return (
<li key={user.id}>
<Link to="{'/users/' + user.id}">{user.name}</Link>
</li>
);
}
});
Container-Komponenten
Container-Komponenten sind fast immer die Eltern von Presentational Components. Sie dienen gewissermaßen als Vermittler zwischen Presentational Components und dem Rest der Anwendung. Sie werden auch als "smarte" Komponenten bezeichnet, da sie sich der Anwendung als Ganzes bewusst sind.
Da Container- und Presentational-Komponenten unterschiedliche Namen haben müssen, nennen wir diese hier UserListContainer, um Verwechslungen zu vermeiden.
var React = require('react');
var axios = require('axios');
var UserList = require('../views/list-user');
var UserListContainer = React.createClass({
getInitialState: function() {
return {
users: []
}
},
componentDidMount: function() {
var _this = this;
axios.get('/path/to/user-api').then(function(response) {
_this.setState({users: response.data})
});
},
render: function() {
return (<UserList users={this.state.users} />);
}
});
module.exports = UserListContainer;
Zur Kürze wurden in diesen Beispielen require()- und module.exports-Anweisungen weggelassen. In diesem Fall ist es jedoch wichtig zu zeigen, dass Container-Komponenten ihre jeweiligen Presentational-Komponenten als direkte Abhängigkeit einbinden. Zur Vollständigkeit zeigt dieses Beispiel alle erforderlichen Abhängigkeiten an.
Container-Komponenten können wie jede andere React-Komponente erstellt werden. Sie haben auch eine render-Methode wie jede andere Komponente, nur dass sie nichts zum Rendern selbst erstellen. Stattdessen geben sie das Ergebnis der Presentational Component zurück.
Ein kurzer Hinweis zu ES6 Arrow Functions: Sie bemerken vielleicht den klassischen Trick var _this = this, der für das obige Beispiel benötigt wird. ES6 Arrow Functions haben neben einer kürzeren Syntax weitere Vorteile, die die Notwendigkeit dieses Tricks beseitigen. Um Ihnen die Konzentration auf das Erlernen von React zu ermöglichen, vermeidet dieses Tutorial die ES6-Syntax zugunsten der älteren ES5-Syntax. Die GitHub-Anleitung für diese Serie verwendet jedoch intensiv ES6 und enthält einige Erklärungen in ihren README-Dateien.
Ereignisse
Bisher haben wir gezeigt, wie State von Container- zu Presentational Components übergeben werden kann, aber was ist mit Verhalten? Ereignisse fallen in die Kategorie Verhalten und sie müssen oft Daten mutieren. Ereignisse in React werden auf der Ansichtsebene angehängt. Zur Trennung der Zuständigkeiten kann dies ein Problem in unseren Presentational Components darstellen, wenn wir Ereignisfunktionen erstellen, wo sich die Ansicht befindet.
Um dies zu verdeutlichen, fügen wir zunächst ein Ereignis zu unserer Presentational Component hinzu (ein <button>, den Sie anklicken können), um Probleme direkt zu identifizieren.
// Presentational Component
var UserList = React.createClass({
render: function() {
return (
<ul className="user-list">
{this.props.users.map(function(user) {
return (
<li key={user.id}>
<Link to="{'/users/' + user.id}">{user.name}</Link>
<button onClick={this.toggleActive}>Toggle Active</button>
</li>
);
})}
</ul>
);
},
toggleActive: function() {
// We shouldn't be changing state in presentational components :(
}
});
Dies würde technisch funktionieren, ist aber keine gute Idee. Wahrscheinlich muss das Ereignis Daten ändern, und Daten, die sich ändern, sollten als State gespeichert werden – etwas, das die Presentational Component nicht kennen sollte.
In unserem Beispiel wäre die State-Änderung die "Aktivität" des Benutzers, aber Sie können beliebige Funktionen erfinden, die Sie an onClick binden möchten.
Eine bessere Lösung ist, Funktionalität von der Container Component in die Presentational Component als Prop zu übergeben, so:
// Container Component
var UserListContainer = React.createClass({
...
render: function() {
return (<UserList users={this.state.users} toggleActive={this.toggleActive} />);
},
toggleActive: function() {
// We should change state in container components :)
}
});
// Presentational Component
var UserList = React.createClass({
render: function() {
return (
<ul className="user-list">
{this.props.users.map(function(user) {
return (
<li key={user.id}>
<Link to="{'/users/' + user.id}">{user.name}</Link>
<button onClick={this.props.toggleActive}>Toggle Active</button>
</li>
);
})}
</ul>
);
}
});
Das onClick-Attribut muss dort sein, wo sich die Ansicht befindet – bei der Presentational Component. Die Funktion, die sie aufruft, wurde jedoch in die übergeordnete Container Component verschoben. Das ist besser, weil die Container Component sich um den State kümmert.
Wenn die übergeordnete Funktion den State ändert, führt die State-Änderung zu einem erneuten Rendern der übergeordneten Funktion, was wiederum die untergeordnete Komponente aktualisiert. Dies geschieht in React automatisch.
Hier ist eine Demo, die zeigt, wie das Ereignis auf der Container Component den State ändern kann, was die Presentational Component automatisch aktualisiert.
Siehe den Pen React Container Component Demo von Brad Westfall (@bradwestfall) auf CodePen.
Beachten Sie, wie dieses Beispiel mit unveränderlichen Daten umgeht und die Methode .bind() verwendet.
Container-Komponenten mit dem Router verwenden
Der Router sollte nicht mehr direkt UserList verwenden. Stattdessen wird er direkt UserListContainer verwenden, der wiederum UserList verwendet. Letztendlich gibt UserListContainer das Ergebnis von UserList zurück, sodass der Router immer noch das erhält, was er benötigt.
Datenfluss und der Spread-Operator
In React wird das Konzept, dass Props von übergeordneten Komponenten an untergeordnete Komponenten weitergegeben werden, als Flow bezeichnet. Die bisherigen Beispiele zeigten nur einfache Eltern-Kind-Beziehungen, aber in einer realen Anwendung könnte es viele verschachtelte Komponenten geben. Stellen Sie sich vor, Daten fließen von übergeordneten Komponenten auf hoher Ebene über State und Props durch viele untergeordnete Komponenten. Dies ist ein grundlegendes Konzept in React und wichtig zu beachten, wenn wir uns dem nächsten Tutorial über Redux zuwenden.
ES6 hat einen neuen Spread-Operator, der sehr nützlich ist. React hat eine ähnliche Syntax zu JSX übernommen. Dies hilft React erheblich bei der Datenfluss über Props. Die GitHub-Anleitung für dieses Tutorial verwendet ihn ebenfalls, lesen Sie daher unbedingt die Anleitungsdokumentation zu dieser Funktion.
Stateless Functional Components
Ab React 0.14 (veröffentlicht Ende 2015) gibt es eine neue Funktion, um zustandslose (Presentational) Komponenten noch einfacher zu erstellen. Die neue Funktion heißt Stateless Functional Components.
Sie haben wahrscheinlich schon bemerkt, dass, wenn Sie Ihre Container- und Presentational-Komponenten trennen, viele Ihrer Presentational-Komponenten nur eine Render-Methode haben. In diesen Fällen erlaubt React jetzt, die Komponente als einzelne Funktion zu schreiben.
// The older, more verbose way
var Component = React.createClass({
render: function() {
return (
<div>{this.props.foo}</div>
);
}
});
// The newer "Stateless Functional Component" way
var Component = function(props) {
return (
<div>{props.foo}</div>
);
};
Sie sehen deutlich, dass der neue Weg kompakter ist. Denken Sie aber daran, dass dies nur eine Option für Komponenten ist, die nur eine render-Methode benötigen.
Mit dem neuen Stateless Functional-Ansatz akzeptiert die Funktion ein Argument für props. Das bedeutet, sie muss nicht this verwenden, um auf Props zuzugreifen.
Hier ist ein sehr gutes Egghead.io-Video zu Stateless Functional Components.
MVC
Wie Sie wahrscheinlich bisher gesehen haben, ähnelt React nicht dem traditionellen MVC. Oft wird React als "nur die Ansichtsschicht" bezeichnet. Das Problem, das ich mit dieser Aussage habe, ist, dass es für React-Anfänger zu leicht ist zu glauben, dass React in ihre vertraute traditionelle MVC-Welt passen *sollte*, als ob es für die Verwendung mit traditionellen Controllern und Modellen von Drittanbietern gedacht wäre.
Obwohl es *stimmt*, dass React keine "traditionellen Controller" hat, bietet es auf seine eigene besondere Weise eine Möglichkeit, Ansichten und Verhalten zu trennen. Ich glaube, dass Container-Komponenten denselben grundlegenden Zweck erfüllen wie ein Controller im traditionellen MVC.
Was die Modelle betrifft, so habe ich Leute gesehen, die Backbone-Modelle mit React verwenden, und ich bin sicher, sie haben alle möglichen Meinungen darüber, ob das für sie gut funktioniert hat. Aber ich bin nicht überzeugt, dass traditionelle Modelle der richtige Weg in
React sind. React möchte Daten so fließen lassen, dass sie nicht gut zu der Funktionsweise traditioneller Modelle passen. Das von Facebook entwickelte Flux-Designmuster ist eine Möglichkeit, Reacts inhärente Fähigkeit zum Datenfluss zu nutzen. Im nächsten Tutorial behandeln wir Redux, eine sehr beliebte Flux-Implementierung und was ich als Alternative zu traditionellen Modellen ansehe.
Zusammenfassung
Container-Komponenten sind eher ein Konzept als eine exakte Lösung. Die Beispiele in diesem Tutorial sind nur eine Möglichkeit, sie umzusetzen. Das Konzept ist jedoch so gut etabliert, dass es sogar Richtlinie von Facebook ist, sie in ihren Teams zu verwenden – auch wenn sie vielleicht andere Terminologien verwenden.
Dieses Tutorial wurde stark von anderen Artikeln zu diesem Thema beeinflusst. Schauen Sie sich unbedingt die offiziellen GitHub-Anleitungen zu diesem Tutorial an, um noch mehr Informationen und ein funktionierendes Beispiel für Container-Komponenten zu erhalten.
Artikelserie
- React Router
- Container-Komponenten (Sie sind hier!)
- Redux
Tolles Thema und toller Artikel – ich freue mich auf Teil 3!
Ist es in React möglich, diesen hässlichen State-Code zu umgehen?
Laut den React-Docs führt
setState()einen flachen Merge durch. Das bedeutet, dass dasuser-Objekt selbst gleich bleibt, obwohl die Referenz darauf in ein neuesstate-Objekt kopiert wird. Warum also nicht das tun?Nach meinem Verständnis und einigem schnellen Ausprobieren in Ihrem CodePen sollte das einwandfrei funktionieren, da es im Wesentlichen genau die gleiche Logik mit viel weniger Code ist.
Was denken Sie?
Danke Agop, tolle Frage. Was Sie also tatsächlich tun, ist,
this.statedirekt zu mutieren, dausereine Referenz aufthis.stateist. Sehen Sie diese Docs https://facebook.github.io/react/docs/component-api.html. Lesen Sie den Abschnitt "Warnung", wo es heißt: "Mutieren Sie niemals this.state direkt".Ich verstehe, dass es mit Ihrer Methode einfacher aussieht, aber State-Mutation ist in React eine große Sache, auf die wir bis zum nächsten Artikel nicht tiefgehend eingehen. Ich hätte mehr Werkzeuge wie lodash oder Immutable.js verwenden können, um meinen Code schöner aussehen zu lassen und trotzdem die Best Practices für Mutation einzuhalten. Aber ich habe versucht, keine weiteren Werkzeuge in das Beispiel einzuführen. Dies war einfach die beste Methode, die mir einfiel, um dies mit Vanilla JS zu tun (allerdings ist
Object.assign()ES6).Brad, die Verwendung von
Object.assign()verhindert nicht, dass der State geändert wird. Wenn SieObject.assign()aufrufen, erhalten Sie eine flache Kopie vonthis.state, die immer noch auf dieselbe Liste von Benutzern verweist (und somit auf dieselben Benutzerobjekte).Dies können Sie mit diesem Code bestätigen
In der Konsole sehen Sie
Sie ändern also immer noch dasselbe Benutzerobjekt, das sich in
this.statebefindet, nur über eine neue Referenz darauf. Sie können dies weiter bestätigen, indem Sie dies nach dem Code hinzufügen, deractiveumschaltet.Hier ist ein kurzer Pen zur Demonstration
http://codepen.io/agop/pen/ONmJRK
Lang gesagt, all dieser Code läuft darauf hinaus, was ich zuvor geschrieben habe
Wenn Sie den State selbst, einschließlich aller darin verschachtelten Objekte, wirklich nicht ändern möchten, müssten Sie eine tiefe Kopie von
this.stateerstellen. Und sobald wir über tiefe Kopien sprechen, müssen wir über Leistung sprechen. Was ist, wenn wir 100 Benutzer hätten? Erstellen wir eine tiefe Kopie aller 100 Benutzer, einschließlich aller ihrer Eigenschaften, nur um eine Eigenschaft eines Benutzers zu aktualisieren?Ich hatte einige ausführliche Slack-Diskussionen mit JS-Freunden und hier ist der Konsens. Erstens sollten wir
this.stateniemals mutieren, wenn wir uns an Best Practices halten, siehe meinen vorherigen Kommentar mit den React-Docs. Zweitens, Sie haben Recht damit, wie ichObject.assign()verwendet habe und dessen Oberflächlichkeit. Was ich hätte tun sollen, istund eine Kopie nur des Benutzers und nicht des gesamten States erstellt. Jetzt ist der Test von
user === newUserfalsch. Das Problem ist nun, dass, da der State ein Array ist, es schwierig ist,newUserin seine ursprüngliche Position "einzuschneiden". Es gibt verschiedene Techniken, aber denken Sie daran, ich habe versucht, neue Werkzeuge wie lodash oder jegliche Komplexität zu vermeiden, die vom Thema ablenkt. Eine Möglichkeit, dies zu tun, ist in diesem alternativen Codepen http://codepen.io/bradwestfall/pen/NNjWLR, wenn man bei keinerlei neuen Werkzeugen und ES6 bleiben möchte. Auch hier ist es nur eine Möglichkeit.Aus Anfängersicht wollte ich eigentlich nur einen Codepen, der das Übergeben einer Funktion über Props von übergeordnet zu untergeordnet demonstriert. Ich wollte mich nicht mit diesem Unveränderlichkeits-Chaos befassen :) Also habe ich den ursprünglichen Pen aktualisiert, um es auf die sehr einfache, veränderliche Weise zu tun – mit dem Hinweis, dass es technisch gesehen keine Best Practice ist. Obwohl Ihr Weg noch weniger Code hat, finde ich ihn für Anfänger verwirrend und themenfremd, da, wie gesagt, der Zweck des Pens ein anderer ist und um es richtig mit Unveränderlichkeit zu machen, müssten wir uns mit vielen anderen Dingen befassen, die nicht der Zweck des Pens sind.
Außerdem, wenn Sie sich Sorgen um die Leistung machen, sind Werkzeuge wie Immutable.js und Reacts eigene Immutability Helpers sehr nützlich http://facebook.github.io/react/docs/update.html
Brad, ich war eigentlich gerade dabei, viel Ähnliches zu schreiben, nachdem ich mich weiter mit Reacts Best Practices beschäftigt habe, aber Sie waren schneller. Also, das stimmt, keiner unserer ursprünglichen Codes (die in Bezug auf das, was tatsächlich mit dem zugrunde liegenden State geschah, identisch waren) entsprach den Best Practices.
Wie Sie wissen und in Ihren Kommentaren genau beschrieben haben, entsprach Ihre aktualisierte Version ebenfalls nicht den Best Practices (neues Benutzerobjekt, aber dieselbe Benutzerliste). Ich würde einige kleine Anpassungen vornehmen, die den Code für die Leser des Artikels einfach halten und gleichzeitig die React-Best Practices für Unveränderlichkeit vollständig einhalten.
Pen
http://codepen.io/agop/pen/grWbqx
Wir haben
this.stateoder seine verschachtelten Eigenschaften nicht modifiziert, aber den Code schön und prägnant gehalten (keine ES6-Nutzung, um es einfach zu halten). So müssen Sie nicht tief in die Tiefen von React und Unveränderlichkeit eintauchen, ohne ein irreführendes Beispiel zu zeigen (seien wir ehrlich, wer wird die Kommentare lesen und wirklich verstehen, dass das Beispiel "fast" unveränderlich ist?).Dies beantwortet auch meine eigene Frage nach tiefen Kopien – wir brauchen keine tiefen Kopien. Wir können auf vorhandene Objekte verweisen und müssen nur flache Kopien von Dingen erstellen, die sich tatsächlich ändern. Wie Sie in Ihrem Kommentar erwähnt haben, kann all dies mit Reacts eigenen Unveränderlichkeitshelfern sowie Dingen wie Immutable-js usw. vereinfacht werden.
Danke Agop, ich denke, wenn jemand das alles liest, wird er sagen, dass der Artikel leicht verständlich war, aber was ist diese Sache mit der Unveränderlichkeit? – zumindest diejenigen, die noch nicht damit in Berührung gekommen sind :) Ich denke, unser Gespräch dokumentiert es für diesen Artikel ausreichend. Die Kommentare des Codepens enthalten tatsächlich einen Link, der auf diese Konversation verweist. Ich werde es so belassen, da der Hauptpunkt des Pens etwas anderes ist. Danke für all Ihr Feedback und den vorgeschlagenen Code.
Brad, es ist Ihr Code, Ihr Artikel, und zwischen Ihnen und mir sind wir eindeutig auf derselben Seite ;)
Dennoch sehe ich keinen Sinn darin, das im Artikel zu belassen
Das ist buchstäblich toter Code. Er tut überhaupt nichts (
users[index] === uservor der Zuweisung sowieso). Er ist nur verwirrend für den Leser, und Sie waren derjenige, der sich gegen die Verwirrung des Lesers ausgesprochen hat (z. B. "Warum weist er den Benutzer im selben Index in dieselbe Liste ein?", "Warum übergibt er dieselbe Liste zurück in den State?", etc.).Mein Code ist von Anfang bis Ende, einschließlich Kommentaren, 16 Zeilen, nur ES5 und sehr leicht verständlich, auch ohne die "Warum"-Fragen der Unveränderlichkeit in React zu behandeln. Ihr Code ist von Anfang bis Ende, einschließlich Kommentaren, 17 Zeilen.
Sie sagen, dass Sie sich in diesem Artikel nicht mit Unveränderlichkeit befassen wollen, und das ist in Ordnung. Dennoch enthält Ihr Code einen 5-zeiligen Kommentarblock, der erklärt, dass er die Best Practices für Unveränderlichkeit nicht einhält, und verlinkt zu einer riesigen Diskussion, die für jemanden, der neu in React ist, absolut keinen Sinn ergeben würde. Mein Code erwähnt die Unveränderlichkeit überhaupt nicht, er folgt ihr einfach.
Lang gesagt, ich versuche nur, den Denkprozess hinter dem Belassen von Code zu verstehen, der die Best Practices nicht einhält, in einem Artikel, der bereits an 5. Stelle steht, wenn man nach Dingen wie "react container components" googelt. Es ist frustrierend für mich zu denken, dass jemand, der neu in React ist, auf diesen Artikel stößt, das Beispiel sieht, schnell den großen Kommentarblock überspringt (kommen Sie schon, wer liest riesige Kommentarblöcke in einem CodePen?) und dann direkt unter dem Beispiel liest
Entschuldigung, ich beende meinen Wutanfall jetzt.
Danke Agop, ich schaue mir das später an :) Ich bin diese Woche mit dem Schreiben des Redux-Artikels beschäftigt, zusammen mit einigen Arbeitsdingen.
Tolles Thema und bisher tolle Artikel!
Ich freue mich auf Teil 3 :)
Ich liebe diese Serie, Brad. Ich hatte beide Artikel gelesen, die Sie als Inspiration zitiert haben, aber das Konzept von Container vs. Presentational hat mir erst beim Lesen dieses Artikels wirklich gefallen. Danke!
Danke Kyle!
Ein riesiges, herzliches Dankeschön, Brad! CSS-Tricks hat mir in den letzten Jahren geholfen, in meinem Handwerk besser zu werden. Ihre Tutorials sind leicht zu befolgen, was ich wirklich mag. Ich freue mich auf Teil 3! :)
Mit freundlichen Grüßen,
Loraine Ortiz
Danke Loraine
Dieser Blogbeitrag wurde in The React Newsletter #23 vorgestellt. http://us4.campaign-archive2.com/?u=29c888baee9c05ccb614e1e92&id=4d59132d66
Hey,
Eine sehr gute Einführung in React-Komponenten!
Ich habe diesen Artikel mit leicht unterschiedlichen Techniken erweitert, wären Sie so freundlich, sich meinen Pen anzusehen: http://codepen.io/bluurn/pen/xVJNWw
Ich wollte nur wissen, ob ich richtig liege (oder nicht :)).
Vielen Dank!
Im Allgemeinen sieht es ziemlich gut aus. Mir ist aufgefallen, dass die Links allerdings nicht funktionieren. Ein Grund dafür könnte sein, dass Sie Anführungszeichen um die geschweiften Klammern gesetzt haben:
<Link to="{'/users/' + user.id}">{user.name}</Link>. Wenn ein Attribut dynamische Teile aus JS verwenden soll, dann setzen Sie keine Anführungszeichen darum. Außerdem hoffe ich, dass Sie auch Teil drei dieser Serie gelesen haben, da Sie dort sehen werden, wie sich das State Management mit Redux unterscheidet – für eine App mit mehreren Komponenten. Danke bluurn