Einer der Vorteile beim Erstellen einer Single Page Application (SPA) ist die extrem schnelle Navigation zwischen den Seiten. Leider sind die Daten unserer Komponenten manchmal erst verfügbar, *nachdem* wir zu einem bestimmten Teil unserer Anwendung navigiert sind. Wir können die wahrgenommene Leistung für den Benutzer verbessern, indem wir die Komponente in zwei Teile aufteilen: den Container (der eine Skelettansicht anzeigt, wenn er leer ist) und den Inhalt. Wenn wir das Rendern der Inhaltskomponente verzögern, bis wir die erforderlichen Inhalte tatsächlich erhalten haben, können wir die Skelettansicht des Containers nutzen und so die wahrgenommene Ladezeit steigern!
Lassen Sie uns mit der Erstellung unserer Komponenten beginnen.
Was wir machen
Wir werden die Skelettkomponente verwenden, die im Artikel „Building Skeleton Screens with CSS Custom Properties“ erstellt wurde.

Dies ist ein großartiger Artikel, der beschreibt, wie Sie eine Skelettkomponente erstellen können, und die Verwendung des :empty-Selektors ermöglicht es uns, geschickt {this.props.children} innerhalb unserer Komponenten zu verwenden, sodass die Skelettkartendie Karte gerendert wird, wenn der Inhalt nicht verfügbar ist.
Sehen Sie sich den Pen React 16 — Skeleton Card – Final von Mathias Rechtzigel (@MathiasaurusRex) auf CodePen an.
Erstellung unserer Komponenten
Wir werden ein paar Komponenten erstellen, um den Einstieg zu erleichtern.
- Der äußere Container (
CardContainer) - Der innere Inhalt (
CardContent)
Zuerst erstellen wir unseren CardContainer. Diese Container-Komponente nutzt den :empty-Pseudoselektor, sodass sie die Skelettansicht rendert, wann immer diese Komponente kein Kind erhält.
class CardContainer extends React.Component {
render() {
return (
<div className="card">
{this.props.children}
</div>
);
}
}
Als Nächstes erstellen wir unsere CardContent-Komponente, die innerhalb unserer CardContainer-Komponente verschachtelt wird.
class CardContent extends React.Component {
render() {
return (
<div className="card--content">
<div className="card-content--top">
<div className="card-avatar">
<img
className="card-avatar--image"
src={this.props.avatarImage}
alt="" />
<span>{this.props.avatarName}</span>
</div>
</div>
<div className="card-content--bottom">
<div className="card-copy">
<h1 className="card-copy--title">{this.props.cardTitle}</h1>
<p className="card-copy--description">{this.props.cardDescription}</p>
</div>
<div className="card--info">
<span className="card-icon">
<span className="sr-only">Total views: </span>
{this.props.countViews}
</span>
<span className="card-icon">
<span className="sr-only">Total comments: </span>
{this.props.countComments}
</span>
</div>
</div>
</div>
);
}
}
Wie Sie sehen können, gibt es ein paar Platzhalter für Eigenschaften, die akzeptiert werden können, wie z. B. ein Avatarbild und ein Name sowie der sichtbare Inhalt der Karte.

Das Zusammenfügen der Komponenten ermöglicht uns die Erstellung einer vollständigen Kartenkomponente.
<CardContainer>
<CardContent
avatarImage='path/to/avatar.jpg'
avatarName='FirstName LastName'
cardTitle='Title of card'
cardDescription='Description of card'
countComments='XX'
countViews='XX'
/>
</CardContainer>
Sehen Sie sich den Pen React 16 — Skeleton Card – Card Content No State von Mathias Rechtzigel (@MathiasaurusRex) auf CodePen an.
Verwendung eines ternären Operators, um Inhalte anzuzeigen, wenn der Zustand geladen wurde
Nachdem wir nun sowohl eine CardContainer- als auch eine CardContent-Komponente haben, haben wir unsere Karte in die notwendigen Teile aufgeteilt, um eine Skelettkomponente zu erstellen. Aber wie wechseln wir zwischen den beiden, wenn Inhalte geladen wurden?
Hier kommen ein cleverer Einsatz von Zustand und ternären Operatoren zur Rettung!
In diesem Abschnitt werden wir drei Dinge tun
- Erstellen Sie ein Zustandsobjekt, das anfänglich auf
falsegesetzt wird - Aktualisieren Sie unsere Komponente, um einen ternären Operator zu verwenden, damit die
cardContent-Komponente nicht gerendert wird, wenn der Zustandfalseist - Setzen Sie den Zustand auf den Inhalt unseres Objekts, sobald wir diese Informationen erhalten haben
Wir möchten, dass der Standardzustand unseres Inhalts auf false gesetzt wird. Dies verbirgt den Karteninhalt und ermöglicht dem CSS-:empty-Selektor, seine Magie zu entfalten.
this.state = {
cardContent: false
};
Nun müssen wir die Kinder unserer CardContainer aktualisieren, um einen ternären Operator einzufügen. In unserem Fall prüft er this.state.cardContent, ob er wahr oder falsch ergibt. Wenn er true ist, wird alles auf der linken Seite des Doppelpunkts (:) ausgeführt. Umgekehrt, wenn er false ist, wird alles auf der rechten Seite des Doppelpunkts ausgeführt. Dies ist ziemlich nützlich, da Objekte zu true aufgelöst werden und wenn wir den anfänglichen Zustand auf false setzen, hat unsere Komponente alle Voraussetzungen, um eine Skelettkomponente zu implementieren!
Fassen wir alles in unserer Hauptanwendung zusammen. Wir werden uns vorerst nicht um den Zustand in CardContent kümmern. Wir werden ihn an einen Button binden, um den Prozess des Abrufens von Inhalten aus einer API zu simulieren.
<CardContainer>
{this.state.cardContent
?
<CardContent
avatarImage={this.state.cardContent.card.avatarImage}
avatarName={this.state.cardContent.card.avatarName}
cardTitle={this.state.cardContent.card.cardTitle}
cardDescription={this.state.cardContent.card.cardDescription}
countComments={this.state.cardContent.card.countComments}
countViews={this.state.cardContent.card.countViews}/>
:
null
}
</CardContainer>
Boom! Wie Sie sehen können, wird die Karte als Skelettkomponente gerendert, da der Zustand von cardContent auf false gesetzt ist. Als Nächstes erstellen wir eine Funktion, die den Zustand von cardContent auf ein Dummy-Karten-Datenobjekt (dummyCardData) setzt.
populateCardContent = (event) => {
const dummyCardData = {
card: {
avatarImage: "https://gravatar.com/avatar/f382340e55fa164f1e3aef2739919078?s=80&d=https://codepen.io/assets/avatars/user-avatar-80x80-bdcd44a3bfb9a5fd01eb8b86f9e033fa1a9897c3a15b33adfc2649a002dab1b6.png",
avatarName: "Mathias Rechtzigel",
cardTitle: "Minneapolis",
cardDescription:"Winter is coming, and it will never leave",
countComments:"52",
countViews:"32"
}
}
const cardContent = dummyCardData
this.setState({
cardContent
})
}
In diesem Beispiel setzen wir den Zustand innerhalb einer Funktion. Wir könnten auch Reacts Lebenszyklusmethoden nutzen, um den Zustand der Komponente zu füllen. Wir müssten die geeignete Methode je nach unseren Anforderungen untersuchen. Wenn ich beispielsweise eine einzelne Komponente lade und die Inhalte aus der API abrufen möchte, würden wir die Lebenszyklusmethode ComponentDidMount verwenden. Wie die Dokumentation besagt, müssen wir vorsichtig sein, diese Lebenszyklusmethode auf diese Weise zu verwenden, da sie möglicherweise ein zusätzliches Rendering verursacht – aber das Setzen des anfänglichen Zustands auf false sollte dies verhindern.
Sehen Sie sich den Pen React 16 — Skeleton Card – Final von Mathias Rechtzigel (@MathiasaurusRex) auf CodePen an.
Die zweite Karte in der Liste ist an das Klickereignis gekoppelt, das den Zustand cardContent setzt. Sobald der Zustand auf das Objekt des Inhalts gesetzt ist, verschwindet die Skelettversion der Karte und der Inhalt wird angezeigt. So wird sichergestellt, dass der Benutzer keinen UI-Flash sieht (die FLU-Saison kommt, also wollen wir den Benutzern keine Grippe geben!).
Lassen Sie uns wiederholen
Wir haben einiges behandelt, also fassen wir zusammen, was wir getan haben.
- Wir haben einen
CardContainererstellt. Die Container-Komponente nutzt den:empty-Pseudoselektor, sodass sie die Skelettansicht der Komponente rendert, wenn diese leer ist. - Wir haben die
CardContent-Komponente erstellt, die innerhalb vonCardContainerverschachtelt ist und an die wir unseren Zustand übergeben. - Wir haben den Standardzustand von
cardContentauffalsegesetzt - Wir verwenden einen ternären Operator, um die innere Inhaltskomponente nur dann zu rendern, wenn wir die Inhalte erhalten und in unser
cardContent-Zustandsobjekt legen.
Und da haben wir es! Eine wahrgenommene Leistungssteigerung durch die Schaffung eines Zwischenzustands zwischen der Anzeige der Benutzeroberfläche und dem Empfang der Daten zur Befüllung des Inhalts.
Es ist etwas verwirrend, dass Sie BEM-ähnliche Syntax auf Ihre eigene Weise verwenden: Wenn
card-copyIhr Block ist, dann solltecard-copy--titleein Modifikator für diesen Block sein (wie ich es erwarte, gemäß der BEM-Konvention), aber in Ihrem Fall ist es eindeutig ein Element eines Blocks, der alscard-copy__titlebenannt werden sollte. Nochmals, ich schlage nicht vor, dass Sie Ihre Klassen *so* schreiben *müssen*, aber wenn ich doppelte Bindestriche oder Unterstriche in kombinierten Klassennamen sehe, erwarte ich sofort BEM zu sehen. Es ist einfach verwirrend.Kein Fan von der Idee eines ternären Operators hier. Wenn Sie eine statische Typisierungslösung wie Flow oder Typescript verwenden würden, wäre das etwas unübersichtlich. Stattdessen könnte es nullbar sein – z. B. wäre der Standard
nullanstelle vonfalse. Sollte genauso gut funktionieren.