Aufbau von Skeleton-Komponenten mit React

Avatar of Mathias Rechtzigel
Mathias Rechtzigel am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

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.

  1. Der äußere Container (CardContainer)
  2. 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

  1. Erstellen Sie ein Zustandsobjekt, das anfänglich auf false gesetzt wird
  2. Aktualisieren Sie unsere Komponente, um einen ternären Operator zu verwenden, damit die cardContent-Komponente nicht gerendert wird, wenn der Zustand false ist
  3. 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.

  1. Wir haben einen CardContainer erstellt. Die Container-Komponente nutzt den :empty-Pseudoselektor, sodass sie die Skelettansicht der Komponente rendert, wenn diese leer ist.
  2. Wir haben die CardContent-Komponente erstellt, die innerhalb von CardContainer verschachtelt ist und an die wir unseren Zustand übergeben.
  3. Wir haben den Standardzustand von cardContent auf false gesetzt
  4. 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.