Ich hatte in letzter Zeit die beste Zeit meines Lebens mit React. Aber auf meiner Reise hatte ich Schwierigkeiten, gute Code-Style-Richtlinien zu finden, um die Mischung aus JSX und JS sauber und lesbar zu halten. Ich habe meine eigenen Styleguides entwickelt, die ich gerne teilen würde. Vielleicht sind diese für Sie nützlich und Sie können natürlich gerne ähnliche Richtlinien im Kommentarbereich unten teilen.
Regel #1: Destrukturieren Sie Ihre props
Eines meiner liebsten ES6-Features ist Destrukturierung. Sie macht die Zuweisung von Objekteigenschaften zu Variablen zu einer viel geringeren Belastung. Werfen wir einen Blick auf ein Beispiel.
Nehmen wir an, wir haben einen Hund, den wir als div mit einer Klasse anzeigen wollen, die nach seiner Rasse benannt ist. Innerhalb des div befindet sich ein Satz, der die Farbe des Hundes angibt und uns sagt, ob er ein guter oder schlechter Hund ist.
class Dog extends Component {
render () {
return <div className={this.props.breed}>My {this.props.color} dog is {this.props.isGoodBoy ? "good" : "bad"}</div>;
}
}
Das tut technisch gesehen alles, was wir wollen, aber es scheint ein ziemlicher Block an Code für nur drei Variablen und ein HTML-Tag zu sein.
Wir können das aufbrechen, indem wir alle Eigenschaften von props lokalen Variablen zuweisen.
let breed = this.props.breed;
let color = this.props.color;
let isGoodBoy = this.props.isGoodBoy;
Mit ES6 können wir das mit einer sauberen Anweisung wie dieser machen
let { breed, color, isGoodBoy } = this.props;
Um alles sauber zu halten, packen wir unseren ternären Operator (mehr dazu später) ebenfalls in seine eigene Variable und voila.
class Dog extends Component {
render () {
let { breed, color, isGoodBoy } = this.props;
let identifier = isGoodBoy ? "good" : "bad";
return <div className={breed}>My {color} dog is {identifier}</div>;
}
}
Viel leichter zu lesen.
Regel #2: Ein Tag, eine Zeile
Nun, wir alle hatten diesen Moment, in dem wir unsere gesamte Funktion in ein Durcheinander aus Operatoren und winzigen Parameternamen verwandeln wollen, um eine verunstaltete, superschnelle, unleserliche Utility-Funktion zu erstellen. Wenn Sie jedoch eine zustandslose Komponente in React erstellen, können Sie dies ziemlich einfach und dennoch sauber tun.
class Dog extends Component {
render () {
let { breed, color, goodOrBad } = this.props;
return <div className={breed}>My {color} dog is {goodOrBad}</div>;
}
}
vs.
let Dog = (breed, color, goodOrBad) => <div className={breed}>My {color} dog is {goodOrBad}</div>;
Wenn Sie nur ein einfaches Element erstellen und Eigenschaften in einem HTML-Tag platzieren, dann machen Sie sich keine Sorgen, all die Funktionen und Wrapper zu bemühen, um eine völlig separate Klasse zu erstellen. Eine Zeile Code reicht aus.
Sie können sogar kreativ mit einigen ES6-Spread-Funktionen umgehen, wenn Sie ein Objekt für Ihre Eigenschaften übergeben. Die Verwendung von this.props.content platziert den String automatisch zwischen dem öffnenden und schließenden Tag.
let propertiesList = {
className: "my-favorite-component",
id: "myFav",
content: "Hello world!"
};
let SimpleDiv = props => <div {... props} />;
let jsxVersion = <SimpleDiv props={propertiesList} />;
Wann man die Spread-Funktion verwendet
- Keine ternären Operatoren erforderlich
- Nur HTML-Tag-Attribute und Inhalt übergeben
- Kann wiederholt verwendet werden
Wann die Spread-Funktion nicht verwendet werden sollte
- Dynamische Eigenschaften
- Array- oder Objekt-Eigenschaften sind erforderlich
- Ein Render, der verschachtelte Tags erfordern würde
Regel #3: Die Regel der 3er
Wenn Sie drei oder mehr Eigenschaften haben, dann schreiben Sie diese sowohl in der Instanz als auch in der Render-Funktion auf eine eigene Zeile.
Das wäre in Ordnung, nur eine Zeile mit Eigenschaften zu haben
class GalleryImage extends Component {
render () {
let { imgSrc, title } = this.props;
return (
<figure>
<img src={imgSrc} alt={title} />
<figcaption>
<p>Title: {title}</p>
</figcaption>
</figure>
);
}
}
Aber betrachten Sie dies
class GalleryImage extends Component {
render () {
let { imgSrc, title, artist, clas, thumbnail, breakpoint } = this.props;
return (
<figure className={clas}>
<picture>
<source media={`(min-width: ${breakpoint})`} srcset={imgSrc} />
<img src={thumbnail} alt={title} />
</picture>
<figcaption>
<p>Title: {title}</p>
<p>Artist: {artist}</p>
</figcaption>
</figure>
);
}
}
Oder das Rendering
<GalleryImage imgSrc="./src/img/vangogh2.jpg" title="Starry Night" artist="Van Gogh" clas="portrait" thumbnail="./src/img/thumb/vangogh2.gif" breakpoint={320} />
Es kann zu viel Codeblock zum Lesen werden. Setzen Sie jede Eigenschaft auf die nächste Zeile für ein sauberes, lesbares Aussehen
let { imgSrc,
title,
artist,
clas,
thumbnail,
breakpoint } = this.props;
und
<GalleryImage
imgSrc="./src/img/vangogh2.jpg"
title="Starry Night"
artist="Van Gogh"
clas="landscape"
thumbnail="./src/img/thumb/vangogh2.gif"
breakpoint={320} />
Regel #4: Zu viele Eigenschaften?
Eigenschaftsmanagement ist auf jeder Ebene knifflig, aber mit ES6-Destrukturierung und dem zustandsbasierten Ansatz von React gibt es einige Möglichkeiten, das Aussehen vieler Eigenschaften aufzuräumen.
Nehmen wir an, wir erstellen eine Mapping-Anwendung, die eine Liste gespeicherter Adressen und eine GPS-Koordinate für Ihren aktuellen Standort hat.
Die aktuellen Benutzerinformationen über Position und Nähe zu Lieblingsadressen sollten sich in der übergeordneten Komponente von App befinden, wie hier
class App extends Component {
constructor (props) {
super(props);
this.state = {
userLat: 0,
userLon: 0,
isNearFavoriteAddress: false
};
}
}
Wenn wir also eine Adresse erstellen und diese die Nähe zur Adresse anzeigen lassen wollen, übergeben wir mindestens zwei Eigenschaften von App.
In der render ()-Methode von App
<Address
... // Information about the address
currentLat={this.state.userLat}
currentLong={this.state.userLon} />
In der Render-Funktion für die Adresskomponente
render () {
let { houseNumber,
streetName,
streetDirection,
city,
state,
zip,
lat,
lon,
currentLat,
currentLon } = this.props;
return ( ... );
}
Bereits jetzt sehen Sie, wie das unhandlich wird. Wenn wir die beiden Informationssätze nehmen und sie in eigene Objekte aufteilen, wird es viel überschaubarer.
In unserem constructor () von App
this.state = {
userPos: {
lat: 0,
lon: 0
},
isNearFavoriteAddress: false
};
Irgendwann vor dem render () von App
let addressList = [];
addressList.push({
houseNumber: "1234",
streetName: "Street Rd",
streetDirection: "N",
city: "City",
state: "ST",
zip: "12345",
lat: "019782309834",
lon: "023845075757"
});
In der render ()-Methode von App
<Address addressInfo={addressList[0]} userPos={this.state.userPos} />
In der Render-Funktion für die Adresskomponente
render () {
let { addressInfo, userPos } = this.props;
let { houseNumber,
streetName,
streetDirection,
city,
state,
zip,
lat,
lon } = addressInfo;
return ( ... );
}
Viel, viel sauberer. React bietet auch einige großartige Möglichkeiten, um sicherzustellen, dass Objekteigenschaften vorhanden sind und einen bestimmten Typ haben, mithilfe von PropTypes, die wir normalerweise nicht in JavaScript haben, was sowieso eine großartige OOP-Sache ist.
Regel #5: Dynamische Renderings – Arrays mappen
Sehr oft schreiben wir in HTML immer wieder die gleichen grundlegenden Code-Stücke, nur mit ein paar wichtigen Unterschieden. Genau dafür wurde React ursprünglich geschaffen. Sie erstellen ein Objekt mit Eigenschaften, das einen komplexen, dynamischen HTML-Block zurückgibt, ohne jeden Teil davon wiederholt schreiben zu müssen.
JavaScript hat bereits eine großartige Möglichkeit, Listen von ähnlichen Informationen zu erstellen: Arrays!
React verwendet die Funktion .map(), um Arrays in Reihenfolge anzuordnen, wobei ein Parameter aus den Arrays als key verwendet wird.
render () {
let pokemon = [ "Pikachu", "Squirtle", "Bulbasaur", "Charizard" ];
return (
<ul>
{pokemon.map(name => <li key={name}>{name}</li>)}
</ul>
);
}
Sie können sogar unsere praktischen Spread-Funktionen verwenden, um eine ganze Liste von Parametern per Objekt über Object.keys() einzuschleusen (wobei wir immer noch einen key benötigen).
render () {
let pokemon = {
"Pikachu": {
type: "Electric",
level: 10
},
"Squirtle": {
type: "Water",
level: 10
},
"Bulbasaur": {
type: "Grass",
level: 10
},
"Charizard": {
type: "Fire",
level: 10
}
};
return (
<ul>
{Object.keys(pokemon).map(name => <Pokemon key={name} {... pokemon[name]} />)}
</ul>
);
}
Regel #6: Dynamische Renderings – React Ternary Operatoren
In React können Sie Operatoren verwenden, um ein bedingtes Rendering durchzuführen, genau wie bei einer Variablendeklaration. In Regel #1 haben wir dies für die Angabe des Zustands unseres Hundes (gut oder schlecht) betrachtet. Es ist nicht unbedingt erforderlich, eine ganze Zeile Code zu erstellen, um einen ein Wort Unterschied in einem Satz zu entscheiden, aber wenn es um große Codeblöcke geht, ist es schwierig, diese kleinen ?'s und :'s zu finden.
class SearchResult extends Component {
render () {
let { results } = this.props;
return (
<section className="search-results">
{results.length > 0 &&
results.map(index => <Result key={index} {... results[index] />)
}
{results.length === 0 &&
<div className="no-results">No results</div>
}
</section>
);
}
}
Oder, in wahrer Ternary-Manier
class SearchResult extends Component {
render () {
let { results } = this.props;
return (
<section className="search-results">
{results.length > 0
? results.map(index => <Result key={index} {... results[index] />)
: <div className="no-results">No results</div>
}
</section>
);
}
}
Selbst mit unserem aufgeräumten Ergebnis-Mapping sehen Sie, wie die Klammern bereits ziemlich dicht verschachtelt sind. Stellen Sie sich nun vor, unser Rendering hätte mehr als nur eine Zeile. Es kann ziemlich schnell unleserlich werden. Betrachten Sie eine Alternative
class SearchResult extends Component {
render () {
let { results } = this.props;
let outputJSX;
if (results.length > 0) {
outputJSX = (
<Fragment>
{results.map(index => <Result key={index} {... results[index] />)}
</Fragment>
);
} else {
outputJSX = <div className="no-results">No results</div>;
}
return <section className="search-results">{outputJSX}</section>;
}
}
Letztendlich ist die Code-Länge ungefähr gleich, aber es gibt einen entscheidenden Unterschied: Beim ersten Beispiel wechseln wir schnell zwischen zwei verschiedenen Syntaxen hin und her, was das visuelle Parsen anstrengend und schwierig macht, während das zweite einfach nur reines JavaScript mit Wertzuweisungen in einer, konsistenten Sprache und einer Einzeilen-Funktionsrückgabe in einer anderen ist.
Die Faustregel in dieser Situation ist, dass wenn das JavaScript, das Sie in Ihr JSX-Objekt einfügen, mehr als zwei Wörter umfasst (z.B. object.property), es vor dem return-Aufruf erfolgen sollte.
Zusammenfassung
Die Kombination von Syntax kann unordentlich werden, und das sind die offensichtlichsten Situationen, in denen ich sah, wie mein Code aus dem Ruder lief. Hier sind die Grundkonzepte, aus denen diese alle stammen und die auf jede Situation angewendet werden können, die hier nicht abgedeckt wurde
- Nutzen Sie ES6-Features. Ernsthaft. Es gibt viele fantastische Features, die Ihre Arbeit einfacher, schneller und viel weniger manuell machen können.
- Schreiben Sie JSX nur auf der rechten Seite eines
=oder einesreturn. - Manchmal brauchen Sie JavaScript in Ihrem JSX. Wenn Ihr JavaScript nicht auf eine Zeile passt (wie eine
.map()-Funktion oder ein ternärer Operator), dann sollte es vorher erledigt werden. - Wenn Ihr Code aussieht wie
(<{`${()}`} />), dann sind Sie wahrscheinlich zu weit gegangen. Nehmen Sie die niedrigste Ebene außerhalb der aktuellen Anweisung und erledigen Sie sie vor der aktuellen.
Ich glaube, dieses Beispiel
sollte sein
Das erste Beispiel destrukturiert die Props nicht.
Regel #5 könnte noch einen Schritt weiter gehen, indem
Object.entriesanstelle vonObject.keysverwendet wird. Kombiniert mit Destrukturierung in Parametern, können Sie ein schönesObject.entries(obj).map(([key, val]) => Dieser Wert ist {val})erzielenSehr schön! Das habe ich noch nicht gesehen, ich werde es anfangen zu benutzen.
Guter Artikel! Ich empfehle definitiv die Verwendung von Prettier, um bei einigen der von Ihnen aufgeführten Formatierungstipps zu helfen.
Nebenbemerkung: Im letzten Beispiel sollten Sie meiner Meinung nach
outputJSXin der Return-Funktion anstelle von nuroutputverwenden.Prost!
Anstelle von "let" verwenden Sie "const" beim Destrukturieren. Sie sollten "let" verwenden, wenn Sie den Wert ändern werden, was hier nicht der Fall ist.
Ich würde wirklich empfehlen,
constanstelle vonletzu verwenden. Das würde die Neuzuweisung von Variablen verhindern, was meiner Meinung nach ein wenig gegen die Konzepte von unveränderlichen Daten verstößt? Wenn die Variable nicht neu zugewiesen wird, sollte sie wirklich nurconstsein, da dies ihr Zweck ist.Ich bin mir nicht sicher, warum Sie
letanstelle vonconstverwenden würden, wenn Sie Ihre Props destrukturieren. Props dürfen nicht mutiert werden und ich würde meine Variablendeklarationen das durch die Verwendung vonconstbekräftigen lassen.Hallo Daniel,
Ich stimme Dwayne zu.
Es lohnt sich, in jedem Artikel über React-Code-Stil zu erwähnen, dass Prettier schnell zum De-facto-JavaScript-„Styleguide“ geworden ist.
Praktisch gesehen beschleunigt es die Entwicklung, indem es Ihnen erlaubt, im „Wild-West“-Stil zu programmieren und dann mit jedem Speichern diesen Code magisch zu bereinigen.
Schauen Sie es sich an!
Bitte verwenden Sie standardmäßig
constund nurlet, wenn es notwendig ist.Machen Sie das nicht
Machen Sie das
Machen Sie das nicht
Mach das
Machen Sie das nicht
Mach das