Der Autor hat Creative Commons dazu ausgewählt, im Rahmen des Programms Write for DOnations eine Spende zu erhalten.
In diesem Tutorial erstellen Sie Wrapper-Komponenten mit Props unter Verwendung der React JavaScript-Bibliothek. Wrapper-Komponenten sind Komponenten, die unbekannte Komponenten umgeben und eine Standardstruktur zum Anzeigen der untergeordneten Komponenten bereitstellen. Dieses Muster ist nützlich zur Erstellung von Elementen der Benutzeroberfläche (UI), die in einem Design wiederholt genutzt werden (zum Beispiel modale Elemente, Vorlagenseiten und Informationskacheln).
Um Wrapper-Komponenten zu erstellen, lernen Sie zunächst, wie man die Rest- und Spread-Operatoren verwendet, um ungenutzte Props zu sammeln und auf verschachtelte Komponenten zu übertragen. Dann erstellen Sie eine Komponente, die die native Komponente children
nutzt, um verschachtelte Komponenten in JSX zu umschließen, als wären sie HTML-Elemente. Abschließend übergeben Sie Komponenten als Props zur Erstellung flexibler Wrapper, die an verschiedenen Stellen in einer Komponente benutzerdefinierte JSX einbetten können.
In diesem Tutorial erstellen Sie Komponenten, um eine Liste von Tierdaten in Form von Karten anzuzeigen. Sie werden lernen, wie man Daten aufteilt und Komponenten umgestaltet, während Sie flexible Wrapping-Komponenten einrichten. Am Ende des Tutorials werden Sie über eine funktionierende Anwendung verfügen, die erweiterte Prop-Verfahren nutzen wird, um wiederverwendbare Komponenten zu erstellen, die sich bei wachsender oder wandelnder Anwendung skalieren und anpassen lassen.
Hinweis: Im ersten Schritt wird ein leeres Projekt eingerichtet, auf dem Sie die Tutorial-Übung aufbauen. Wenn Sie bereits ein Arbeitsprojekt haben und direkt mit Requisiten arbeiten möchten, beginnen Sie mit Schritt 2.
Sie benötigen eine Entwicklungsumgebung, die Node.js ausführt; dieses Tutorial wurde mit der Node.js-Version 10.20.1 und der npm-Version 6.14.4 getestet. Um dies unter MacOS oder Ubuntu 18.04 zu installieren, folgen Sie den Schritten in Installieren von Node.js und Erstellen einer lokalen Entwicklungsumgebung unter MacOS oder dem Abschnitt Installieren unter Verwendung eines PPA von Installieren von Node.js unter Ubuntu 18.04.
In diesem Tutorial erstellen Sie eine App mit Create React App. Anweisungen zur Installation einer Anwendung mit Create React App und allgemeine Informationen zur Funktionsweise finden Sie unter Einrichten eines React-Projekts mit Create React App.
Sie werden React-Komponenten nutzen, über die Sie in unserem Tutorial Erstellen von benutzerdefinierten Komponenten in React mehr erfahren können. Dabei erhalten Sie auch grundlegende Kenntnisse zu React-Props; siehe Anpassen von React-Komponenten mit Props.
Außerdem benötigen Sie Grundkenntnisse zu JavaScript, die Sie in unserer Reihe Codieren in JavaScript finden, sowie Grundkenntnisse zu HTML und CSS. Eine gute Ressource für HTML und CSS ist das Mozilla Developer Network.
In diesem Schritt erstellen Sie unter Verwendung der Create React App eine Grundlage für Ihr Projekt. Anschließend löschen Sie das Beispielprojekt und die zugehörigen Dateien, die beim Urladen des Projekts installiert werden. Schließlich erstellen Sie eine einfache Dateistruktur, um Ihre Komponenten zu organisieren. Auf diese Weise erhalten Sie eine solide Basis, auf der Sie im nächsten Schritt die Wrapper-Anwendung dieses Tutorials aufbauen können.
Beginnen Sie mit der Erstellung eines neuen Projekts. Führen Sie auf Ihrer Befehlszeile das folgende Skript aus, um ein neues Projekt mit create-react-app
zu installieren:
- npx create-react-app wrapper-tutorial
Nachdem das Projekt erstellt ist, wechseln Sie in das Verzeichnis:
- cd wrapper-tutorial
Starten Sie das Projekt in einer neuen Terminal-Registerkarte oder einem -fenster mit dem Create React App start-Skript. Der Browser wird bei Änderungen automatisch aktualisiert. Lassen Sie das Skript während des Arbeitens also laufen:
- npm start
Sie erhalten einen funktionierenden lokalen Server. Falls das Projekt nicht in einem Browserfenster geöffnet wurde, können Sie es über http://localhost:3000/
öffnen. Wenn Sie dies von einem Remote-Server aus ausführen, ist die Adresse http://your_domain:3000
.
Ihr Browser wird mit einer einfachen React-Anwendung geladen, die Teil der Create React App ist:
Sie werden ein vollständig neues Set von benutzerdefinierten Komponenten erstellen, sodass Sie zunächst etwas Standardcode löschen müssen, um ein leeres Projekt zu erhalten.
Zuerst öffnen Sie src/App.js
in einem Texteditor. Das ist die Root-Komponente, die in der Seite injiziert ist. Alle Komponenten beginnen von hier. Weitere Informationen zu App.js
finden Sie unter Wie man ein React-Projekt mit Create React App einrichtet.
Öffnen Sie src/App.js
mit dem folgenden Befehl:
- nano src/App.js
Sie sehen eine Datei wie diese:
import React from 'react';
import logo from './logo.svg';
import './App.css';
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
Löschen Sie die Zeile Logo aus '/logo.svg'; importieren
. Ersetzen Sie dann alles in der return
-Anweisung, um eine Reihe leerer Tags zurückzugeben: <></>
. Dadurch erhalten Sie eine gültige Seite, die nichts zurückgibt. Der endgültige Code sieht so aus:
import React from 'react';
import './App.css';
function App() {
return <></>;
}
export default App;
Speichern und schließen Sie den Texteditor.
Abschließend löschen Sie das Logo. Sie werden es nicht in Ihrer Anwendung verwenden und Sie sollten unbenutzte Dateien entfernen, während Sie arbeiten. Das wird Sie auf lange Sicht vor Unordnung bewahren.
Geben Sie im Terminalfenster den folgenden Befehl ein:
- rm src/logo.svg
Wenn Sie in Ihren Browser schauen, sehen Sie einen leeren Bildschirm.
Nachdem Sie das Beispielprojekt React App erstellen gelöscht haben, erstellen Sie eine einfache Dateistruktur. Dies hilft Ihnen, Ihre Komponenten isoliert und unabhängig zu halten.
Erstellen Sie im Verzeichnis src
ein Verzeichnis mit dem Namen Komponenten
. Es wird alle Ihre benutzerdefinierten Komponenten enthalten.
- mkdir src/components
Jede Komponente verfügt über ein eigenes Verzeichnis zum Speichern der Komponentendatei zusammen mit den Stilen, gegebenenfalls Bildern und Tests.
Erstellen Sie ein Verzeichnis für App
:
- mkdir src/components/App
Verschieben Sie alle App
-Dateien in dieses Verzeichnis. Verwenden Sie die wildcard, *
, um alle mit App.
beginnenden Dateien auszuwählen, unabhängig von der Dateierweiterung. Verwenden Sie dann den Befehl mv
, um sie in das neue Verzeichnis zu platzieren.
- mv src/App.* src/components/App
Aktualisieren Sie als Nächstes den relativen Importpfad in index.js
. Dabei handelt es sich um die root-Komponente, die den gesamten Prozess bootet.
- nano src/index.js
Die Import-Anweisung muss auf die Datei App.js
im App
-Verzeichnis verweisen. Nehmen Sie daher die folgende hervorgehobene Änderung vor:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './components/App/App';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
Speichern und schließen Sie die Datei.
Nachdem das Projekt eingerichtet wurde, können Sie Ihre erste Komponente erstellen.
...props
In diesem Schritt erstellen Sie eine Komponente, um einen Datensatz über eine Gruppe von Tieren anzuzeigen. Ihre Komponente wird eine zweite verschachtelte Komponente enthalten, um einige Daten visuell darzustellen. Um die übergeordnete und verschachelte Komponente zu verbinden, nutzen Sie die Rest- und Spread-Operatoren, um ungenutzte Props vom übergeordneten Element an das untergeordnete Element zu übergeben, ohne dass das übergeordnete Element die Namen oder Arten der Props kennen muss.
Am Ende dieses Schritts verfügen Sie über eine übergeordnete Komponente, die Props für verschachtelte Komponenten bereitstellen kann, ohne wissen zu müssen, um welche Props es sich handelt. Dadurch bleibt die übergeordnete Komponente flexibel, sodass Sie die untergeordnete Komponente aktualisieren können, ohne das übergeordnete Element ändern zu müssen.
AnimalCard
-KomponenteErstellen Sie zunächst einen Datensatz für Ihre Tiere. Öffnen Sie zuerst eine Datei mit den Daten im Verzeichnis components/App
:
- nano src/components/App/data.js
Fügen Sie die folgenden Daten hinzu:
export default [
{
name: 'Lion',
scientificName: 'Panthero leo',
size: 140,
diet: ['meat']
},
{
name: 'Gorilla',
scientificName: 'Gorilla beringei',
size: 205,
diet: ['plants', 'insects']
},
{
name: 'Zebra',
scientificName: 'Equus quagga',
size: 322,
diet: ['plants'],
}
]
Diese Liste mit Tieren ist ein Array von Objekten, das den Namen, den wissenschaftlichen Namen, das Gewicht und die Ernährung des jeweiligen Tiers beinhaltet.
Speichern und schließen Sie die Datei.
Erstellen Sie als Nächstes ein Verzeichnis für die AnimalCard
-Komponente:
- mkdir src/components/AnimalCard
Öffnen Sie eine neue Datei im Verzeichnis:
- nano src/components/AnimalCard/AnimalCard.js
Fügen Sie nun eine Komponente hinzu, die den Namen
, die Ernährung
und die Größe
als Prop nutzen und anzeigen wird.
import React from 'react';
import PropTypes from 'prop-types';
export default function AnimalCard({ diet, name, size }) {
return(
<div>
<h3>{name}</h3>
<div>{size}kg</div>
<div>{diet.join(', ')}.</div>
</div>
)
}
AnimalCard.propTypes = {
diet: PropTypes.arrayOf(PropTypes.string).isRequired,
name: PropTypes.string.isRequired,
size: PropTypes.number.isRequired,
}
Hier destrukturieren Sie die Props in der Parameterliste für die Funktion AnimalCard
und zeigen die Daten dann in einem div
an. Die diet
-Daten werden mit der Methode join()
als einzelne Zeichenfolge aufgelistet. Jedes Datenstück enthält einen entsprechenden PropType
, um sicherzustellen, dass der Datentyp korrekt ist.
Speichern und schließen Sie die Datei.
Nachdem Sie über Ihre Komponente und Ihre Daten verfügen, müssen Sie sie nun miteinander kombinieren. Importieren Sie dazu die Komponente und die Daten in die root-Komponente Ihres Projekts: App.js
.
Öffnen Sie zunächst die Komponente:
- nano src/components/App/App.js
Von dort aus können Sie eine Schleife über die Daten durchlaufen und eine neue AnimalCard
mit den entsprechenden Props zurückgeben. Fügen Sie die hervorgehobenen Zeilen zu App.js
hinzu:
import React from 'react';
import './App.css';
import animals from './data';
import AnimalCard from '../AnimalCard/AnimalCard';
function App() {
return (
<div className="wrapper">
{animals.map(animal =>
<AnimalCard
diet={animal.diet}
key={animal.name}
name={animal.name}
size={animal.size}
/>
)}
</div>
);
}
export default App;
Speichern und schließen Sie die Datei.
Wenn Sie an komplexeren Projekten arbeiten, werden Ihre Daten aus diverseren Quellen stammen (z. B. APIs, lokalem Speicher
oder statischen Dateien). Der Prozess zur Verwendung der jeweiligen Daten ähnelt sich jedoch: Weisen Sie die Daten einer Variable zu und durchlaufen Sie eine Schleife über die Daten. In diesem Fall stammen sie aus einer statischen Datei, sodass Sie sie direkt in eine Variable importieren.
In diesem Code nutzen Sie die .map()
-Methode, um über animals
zu iterieren und die Props anzuzeigen. Beachten Sie, dass Sie nicht alle Daten verwenden müssen. Sie übergeben beispielsweise die Eigenschaft scientificName
nicht explizit. Außerdem fügen Sie einen separaten Schlüssel
-Prop hinzu, den React zum Verfolgen der abgebildeten Daten nutzen wird. Schließlich umschließen Sie den Code durch ein div
mit dem className
wrapper
, den Sie zum Hinzufügen von Formatierungselementen nutzen werden.
Öffnen Sie zum Hinzufügen der Formatierungselemente App.css
:
- nano src/components/App/App.css
Entfernen Sie die Formatierungsbausteine und fügen Sie flex properties einer Klasse namens wrapper
hinzu:
.wrapper {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
padding: 20px;
}
Dadurch wird ein Flexbox-Layout genutzt, um die Daten zu organisieren und auszurichten. padding
schafft ein wenig Platz im Browserfenster, während justify-content
den Platz zwischen Elementen vergrößert.
Speichern und schließen Sie die Datei. Wenn Sie dies tun, wird der Browser aktualisiert und Sie sehen einige Daten im Abstand.
Sie verfügen nun über eine einfache Komponente, die die Daten anzeigt. Nehmen wir jedoch an, dass Sie die diet
-Daten etwas aufpeppen möchten, indem Sie den Text in ein Emoji verwandeln. Sie können dazu die Daten in Ihrer Komponente konvertieren.
React ist so konzipiert, dass es besonders flexibel ist. Wenn Sie also überlegen, wie Sie Daten konvertieren sollen, haben Sie verschiedene Optionen:
Jeder Ansatz ist in Ordnung, wenn er auf den richtigen Anwendungsfall angewendet wird; Sie werden beim Einrichten einer Anwendung wahrscheinlich zwischen den verschiedenen Ansätzen wechseln. Um vorzeitige Abstraktion und Komplexität zu vermeiden, sollten Sie mit der ersten Option starten. Wenn Sie Logik wiederverwenden möchten, können Sie die Funktion separat aus der Komponente extrahieren. Die dritte Option ist die beste, wenn Sie ein wiederverwendbares Stück haben möchten, das die Logik und das Markup enthält oder das Sie in der Anwendung isoliert verwenden möchten.
In diesem Fall erstellen wir eine neue Komponente, da wir später mehr Daten hinzufügen wollen und Markup mit der Konvertierungslogik kombinieren.
Die neue Komponente erhält den Namen AnimalDetails
. Erstellen Sie dazu ein neues Verzeichnis:
- mkdir src/components/AnimalDetails
Öffnen Sie als Nächstes AnimalDetails.js
in Ihrem Texteditor:
- nano src/components/AnimalDetails/AnimalDetails.js
Erstellen Sie in der Datei eine kleine Komponente, die die diet
(Ernährung) als Emoji anzeigt:
import React from 'react';
import PropTypes from 'prop-types';
import './AnimalDetails.css';
function convertFood(food) {
switch(food) {
case 'insects':
return '🐜';
case 'meat':
return '🍖';
case 'plants':
default:
return '🌱';
}
}
export default function AnimalDetails({ diet }) {
return(
<div className="details">
<h4>Details:</h4>
<div>
Diet: {diet.map(food => convertFood(food)).join(' ')}
</div>
</div>
)
}
AnimalDetails.propTypes = {
diet: PropTypes.arrayOf(PropTypes.string).isRequired,
}
Das Objekt AnimalDetails.propTypes
richtet die Funktion so ein, dass ein Prop von diet
verwendet wird. Dabei handelt es sich um ein Array von Zeichenfolgen. Dann durchläuft der Code in der Komponente eine Schleife über diet
und wandelt die Zeichenfolge mit der Anweisung switch in ein Emoji um.
Speichern und schließen Sie die Datei.
Außerdem importieren Sie einige CSS. Fügen wir das also jetzt hinzu.
Öffnen Sie AnimalDetails.css
:
- nano src/components/AnimalDetails/AnimalDetails.css
Fügen Sie einige CSS hinzu, um dem Element einen Rahmen und Rand zu verleihen und die Details vom Rest der Komponente zu trennen:
.details {
border-top: gray solid 1px;
margin: 20px 0;
}
Wir nutzen .details
, um die Regel mit Elementen, die den className
details
tragen, abzustimmen.
Speichern und schließen Sie die Datei.
Nachdem Sie über eine neue benutzerdefinierte Komponente verfügen, können Sie sie nun Ihrer AnimalCard
-Komponente hinzufügen. Öffnen Sie AnimalCard.js
:
- nano src/components/AnimalCard/AnimalCard.js
Ersetzen Sie die Anweisung diet.join
durch die neue AnimalDetails
-Komponente und übergeben Sie diet
als Prop, indem Sie die hervorgehobenen Zeilen hinzufügen:
import React from 'react';
import PropTypes from 'prop-types';
import AnimalDetails from '../AnimalDetails/AnimalDetails';
export default function AnimalCard({ diet, name, size }) {
return(
<div>
<h3>{name}</h3>
<div>{size}kg</div>
<AnimalDetails
diet={diet}
/>
</div>
)
}
AnimalCard.propTypes = {
diet: PropTypes.arrayOf(PropTypes.string).isRequired,
name: PropTypes.string.isRequired,
size: PropTypes.number.isRequired,
}
Speichern Sie die Datei; die neuen Details werden im Browser angezeigt.
...props
Die Komponenten funktionieren gut zusammen, in AnimalCard
gibt es jedoch eine kleine Unzulänglichkeit. Sie extrahieren diet
explizit aus dem Argument props
, nutzen die Daten aber nicht. Stattdessen übergeben Sie sie an die Komponente. Daran ist nichts grundsätzlich falsch: So ist es oft besser, bei zu viel Kommunikation auf der sicheren Seite zu bleiben. Das erschwert jedoch die Pflege Ihres Codes. Wenn Sie neue Daten an AnimalDetails
übergeben möchten, müssen Sie drei Stellen aktualisieren: App
, wo Sie die Props übergeben, AnimalDetails
, was das Prop konsumiert, und AnimalCard
, was als Vermittler dient.
Eine bessere Methode besteht darin, alle ungenutzten Props in AnimalCard
zu sammeln und diese dann direkt an AnimalDetails
zu übergeben. Dadurch erhalten Sie die Möglichkeit, Änderungen an AnimalDetails
vorzunehmen, ohne AnimalCard
zu ändern. In Wahrheit muss AnimalCard
nichts über die Props oder PropTypes
wissen, die in AnimalDetails
einfließen.
Dazu verwenden Sie den object rest-Operator. Dieser Operator sammelt alle Elemente, die während der Destrukturierung nicht extrahiert werden, und speichert sie in einem neuen Objekt.
Hier ist ein einfaches Beispiel:
const dog = {
name: 'dog',
diet: ['meat']
}
const { name, ...props } = dog;
In diesem Fall werden die Variable name
'dog'
und die Variable props
{ diet: ['meat']}
lauten.
Bisher haben Sie alle Props so übergeben, als wären sie HTML-Attribute; Sie können zum Senden von Props jedoch auch Objekte verwenden. Um ein Objekt als Prop zu verwenden, müssen Sie den Spread-Operator – ...props
– mit geschweiften Klammern umgeben. Dadurch wird jedes Schlüssel-Wert-Paar in ein Prop geändert.
Öffnen Sie AnimalCard.js
:
- nano src/components/AnimalCard/AnimalCard.js
Entfernen Sie diet
aus dem destrukturierten Objekt und sammeln Sie stattdessen den Rest der Props in einer Variable namens props
. Übergeben Sie diese Props dann direkt an AnimalDetails
:
import React from 'react';
import PropTypes from 'prop-types';
import AnimalDetails from '../AnimalDetails/AnimalDetails';
export default function AnimalCard({ name, size, ...props }) {
return(
<div>
<h3>{name}</h3>
<div>{size}kg</div>
<AnimalDetails
{...props}
/>
</div>
)
}
AnimalCard.propTypes = {
name: PropTypes.string.isRequired,
size: PropTypes.number.isRequired,
}
Beachten Sie, dass Sie den diet
-PropType
entfernen können, da Sie das Prop in dieser Komponente nicht verwenden.
In diesem Fall übergeben Sie nur ein Prop an AnimalDetails
. In Fällen, in denen Sie über mehrere Props verfügen, ist die Reihenfolge von Bedeutung. Ein späteres Prop wird frühere Props überschreiben. Wenn Sie über ein Prop verfügen, das Priorität haben soll, müssen Sie also sicherstellen, dass es an letzter Stelle steht. Dies kann zu Verwirrung führen, wenn Ihr props
-Objekt eine Eigenschaft hat, die auch ein benannter Wert ist.
Speichern und schließen Sie die Datei. Der Browser wird aktualisiert und alles wird unverändert aussehen:
Um zu sehen, wie das Objekt ...props
die Flexibilität erhöht, übergeben wir den scientificName
an AnimalDetails
über die Komponente AnimalCard
.
Öffnen Sie zunächst App.js
:
- nano src/components/App/App.js
Übergeben Sie dann den scientificName
als Prop:
import React from 'react';
import './App.css';
import animals from './data';
import AnimalCard from '../AnimalCard/AnimalCard';
function App() {
return (
<div className="wrapper">
{animals.map(animal =>
<AnimalCard
diet={animal.diet}
key={animal.name}
name={animal.name}
size={animal.size}
scientificName={animal.scientificName}
/>
)}
</div>
);
}
export default App;
Speichern und schließen Sie die Datei.
Überspringen Sie AnimalCard
; hier müssen Sie keine Änderungen vornehmen. Öffnen Sie dann AnimalDetails
, um das neue Prop zu verwenden:
- nano src/components/AnimalDetails/AnimalDetails.js
Das neue Prop ist eine Zeichenfolge, die Sie der Liste details
zusammen mit einer Zeile hinzufügen, die den PropType
deklariert:
import React from 'react';
...
export default function AnimalDetails({ diet, scientificName }) {
return(
<div className="details">
<h4>Details:</h4>
<div>
Scientific Name: {scientificName}.
</div>
<div>
Diet: {diet.map(food => convertFood(food)).join(' ')}
</div>
</div>
)
}
AnimalDetails.propTypes = {
diet: PropTypes.arrayOf(PropTypes.string).isRequired,
scientificName: PropTypes.string.isRequired,
}
Speichern und schließen Sie die Datei. Danach wird der Browser aktualisiert und Sie sehen die neuen Details ohne jegliche Änderungen an der Komponente AnimalCard
:
In diesem Schritt haben Sie gelernt, wie Sie flexible übergeordnete Props erstellen, die unbekannte Props nutzen und mit dem Spread-Operator in verschachtelte Komponenten übergeben können. Dies ist ein häufiges Muster, das Ihnen die Flexibilität verleiht, die Sie zur Erstellung von Komponenten mit fokussierten Aufgaben benötigen. Im nächsten Schritt erstellen Sie Komponenten, die mit dem nativen Prop children
unbekannte Komponenten als Prop verwenden können.
children
In diesem Schritt erstellen Sie eine Wrapper-Komponente, die eine unbekannte Gruppe von Komponenten als Prop verwenden kann. Dadurch erhalten Sie die Möglichkeit, Komponenten wie Standard-HTML zu verschachteln. Außerdem erhalten Sie ein Muster zum Erstellen von wiederverwendbaren Wrappern, sodass Sie eine Vielzahl von Komponenten erstellen können, die ein einheitliches Design bei einen flexiblen Inneren aufweisen.
React bietet Ihnen ein natives Prop namens children
, das alle untergeordneten Komponenten sammelt. Dadurch wird die Erstellung von Wrapper-Komponenten intuitiv und lesbar.
Erstellen Sie zunächst eine neue Komponente namens Card
. Das wird eine Wrapper-Komponente sein, um ein neues Standardformat für alle neuen Kartenkomponenten zu erstellen.
Erstellen Sie ein neues Verzeichnis:
- mkdir src/components/Card
Öffnen Sie dann die Komponente Card
in Ihrem Texteditor:
- nano src/components/Card/Card.js
Erstellen Sie eine Komponente, die children
und title
als Props verwendet und in einem div
umschließt, indem Sie den folgenden Code hinzufügen:
import React from 'react';
import PropTypes from 'prop-types';
import './Card.css';
export default function Card({ children, title }) {
return(
<div className="card">
<div className="card-details">
<h2>{title}</h2>
</div>
{children}
</div>
)
}
Card.propTypes = {
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.element),
PropTypes.element.isRequired
]),
title: PropTypes.string.isRequired,
}
Die PropTypes
für die children
(untergeordneten Elemente) sind neu. Das Prop children
kann entweder ein JSX-Element oder ein Array von JSX-Elementen sein. Der title
(Titel) ist eine Zeichenfolge.
Speichern und schließen Sie die Datei.
Fügen Sie als Nächstes einige Formatierungselemente hinzu. Öffnen Sie Card.css
:
- nano src/components/Card/Card.css
Ihre Karte wird einen Rahmen und eine Linie unter den Details aufweisen.
.card {
border: black solid 1px;
margin: 10px;
padding: 10px;
width: 200px;
}
.card-details {
border-bottom: gray solid 1px;
margin-bottom: 20px;
}
Speichern und schließen Sie die Datei. Nachdem Sie über Ihre Komponente verfügen, müssen Sie sie verwenden. Sie könnten jede AnimalCard
mit der Komponente Card
in App.js
umschließen, da der Name AnimalCard
jedoch impliziert, dass es sich bereits um eine Card
handelt, wäre es besser, die Komponente Card
innerhalb von AnimalCard
zu verwenden.
Öffnen Sie AnimalCard
:
- nano src/components/AnimalCard/AnimalCard.js
Im Gegensatz zu anderen Props übergeben Sie children
jedoch nicht explizit. Stattdessen schließen Sie die JSX, als wären sie untergeordnete HTML-Elemente. Anders ausgedrückt: Sie verschachteln sie einfach innerhalb des Elements (wie folgt):
import React from 'react';
import PropTypes from 'prop-types';
import Card from '../Card/Card';
import AnimalDetails from '../AnimalDetails/AnimalDetails';
export default function AnimalCard({ name, size, ...props }) {
return(
<Card title="Animal">
<h3>{name}</h3>
<div>{size}kg</div>
<AnimalDetails
{...props}
/>
</Card>
)
}
AnimalCard.propTypes = {
name: PropTypes.string.isRequired,
size: PropTypes.number.isRequired,
}
Anders als bei einer React-Komponente müssen Sie kein einziges root-Element als untergeordnetes Element verwenden. Deshalb hat der PropType
für Card
angegeben, dass es sich um ein Array von Elementen oder ein einzelnes Element handeln kann. Zusätzlich zur Übergabe der children
(untergeordneten Elemente) als verschachtelte Komponenten geben Sie der Karte den Namen Animal
.
Speichern und schließen Sie die Datei. Danach wird der Browser aktualisiert und Sie sehen die aktualisierte Kartenkomponente.
Sie verfügen nun über eine wiederverwendbare Card
-Komponente, die eine beliebige Anzahl von verschachtelten untergeordneten Elementen aufnehmen kann. Der Hauptvorteil besteht darin, dass Sie die Card
(Karte) mit beliebigen Komponenten wiederverwenden können. Würden Sie eine Plant
-Karte erstellen wollen, könnten Sie dazu die Pflanzendaten mit der Card
-Komponente umschließen. Es muss nicht einmal eine Beziehung vorhanden sein: Sollten Sie die Card
-Komponente in einer völlig anderen Anwendung wiederverwenden wollen, die zum Beispiel Musik oder Kontodaten auflisten, ist das ebenfalls möglich. Der Komponente Card
ist es egal, woraus die untergeordneten Elemente bestehen; Sie verwenden das Wrapper-Element einfach wieder (in diesem Fall den formatierten Rahmen und Titel).
Der Nachteil von children
besteht darin, dass es lediglich eine Instanz des untergeordneten Prop geben kann. Hin und wieder benötigen Sie aber wahrscheinlich eine Komponente, die benutzerdefinierte JSX an mehreren Stellen aufweist. Zum Glück können Sie dazu JSX- und React-Komponenten als Props übergeben, worauf wir im nächsten Schritt eingehen werden.
In diesem Schritt verändern Sie Ihre Card
-Komponente, damit sie andere Komponenten als Props nutzt. Dadurch erhält Ihre Komponente maximale Flexibilität, um unbekannte Komponenten oder JSX auf der Seite an verschiedenen Stellen anzuzeigen. Im Gegensatz zu children
(untergeordneten Elementen), die Sie nur einmal verwenden können, können Sie so viele Komponenten wie Props nutzen. So lässt sich Ihre Wrapper-Komponente an eine Vielzahl von Bedürfnissen anpassen, während die standardmäßige Optik und Struktur gewahrt bleiben.
Am Ende dieses Schritts werden Sie über eine Komponente verfügen, die untergeordnete Komponenten umschließen und auch andere Komponenten in der Karte anzeigen kann. Dieses Muster bietet Ihnen Flexibilität, wenn Sie Komponenten erstellen möchten, die Daten benötigen, die komplexer als einfache Zeichenfolgen und Ganzzahlen sind.
Wir wollen die Komponente Card
so ändern, dass sie ein willkürliches React-Element namens details
nutzt.
Öffnen Sie zunächst die Card
-Komponente:
- nano src/components/Card/Card.js
Fügen Sie als Nächstes ein neues Prop namens details
hinzu und platzieren Sie es unter dem Element <h2>
:
import React from 'react';
import PropTypes from 'prop-types';
import './Card.css';
export default function Card({ children, details, title }) {
return(
<div className="card">
<div className="card-details">
<h2>{title}</h2>
{details}
</div>
{children}
</div>
)
}
Card.propTypes = {
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.element),
PropTypes.element.isRequired
]),
details: PropTypes.element,
title: PropTypes.string.isRequired,
}
Card.defaultProps = {
details: null,
}
Dieses Prop wird den gleichen Typ wie children
aufweisen, sollte jedoch optional sein. Um es optional zu machen, fügen Sie einen Standardwert von null
hinzu. In diesem Fall wird die Komponente, wenn ein Benutzer keine Details übergibt, dennoch gültig sein und nichts Zusätzliches anzeigen.
Speichern und schließen Sie die Datei. Die Seite wird aktualisiert und Sie sehen das gleiche Bild wie zuvor:
Fügen Sie der AnimalCard
nun einige Details hinzu. Öffnen Sie zunächst AnimalCard
.
- nano src/components/AnimalCard/AnimalCard.js
Da die Card
-Komponente children
bereits verwendet, müssen Sie die neue JSX-Komponente als Prop übergeben. Da es sich jeweils um Säugetiere handelt, fügen Sie dies der Karte hinzu, umschließen es jedoch mit <em>
-Tags, um Kursivschrift anzuwenden.
import React from 'react';
...
export default function AnimalCard({ name, size, ...props }) {
return(
<Card title="Animal" details={<em>Mammal</em>}>
<h3>{name}</h3>
<div>{size}kg</div>
<AnimalDetails
{...props}
/>
</Card>
)
}
...
Speichern Sie die Datei. Daraufhin wird der Browser aktualisiert und Sie sehen die Aktualisierung, einschließlich der Phrase Säugetier.
Dieses Prop ist bereits leistungsstark, da es JSX beliebiger Größe verwenden kann. In diesem Beispiel haben Sie nur ein einziges Element hinzugefügt; Sie könnten jedoch so viele JSX übergeben, wie Sie wollen. Es muss auch nicht JSX sein. Wenn Sie beispielsweise über kompliziertes Markup verfügen, würden Sie es nicht direkt im Prop übergeben wollen. Das wäre schwierig zu lesen. Stattdessen könnten Sie eine separate Komponente erstellen und die Komponente dann als Prop übergeben.
Um dies in der Praxis zu sehen, übergeben Sie AnimalDetails
an das Prop details
:
import React from 'react';
...
export default function AnimalCard({ name, size, ...props }) {
return(
<Card
title="Animal"
details={
<AnimalDetails
{...props}
/>
}
>
<h3>{name}</h3>
<div>{size}kg</div>
</Card>
)
}
...
AnimalDetails
ist komplizierter und weist eine Reihe von Markup-Zeilen auf. Würden Sie dies direkt zu details
hinzufügen, würde das Prop wesentlich größer und damit schwerer zu lesen.
Speichern und schließen Sie die Datei. Daraufhin wird der Browser aktualisiert und die Details erscheinen oben auf der Karte.
Sie verfügen nun über eine Card
-Komponente, die benutzerdefinierte JSX verwenden und an verschiedenen Stellen platzieren kann. Sie sind nicht auf einzelne Props beschränkt; vielmehr können Sie Elemente an so viele Props übergeben, wie Sie möchten. So können Sie flexible Wrapping-Komponenten erstellen, die anderen Entwicklern die Möglichkeit bieten, eine Komponente anzupassen, während ihre Gesamtformatierung und -funktionalität beibehalten werden.
Das Übergeben einer Komponente als Prop ist nicht perfekt. Ein Prop ist etwas schwieriger zu lesen und nicht so klar wie das Übergeben von children
(untergeordneten Elementen). Es ist jedoch genauso flexibel und kann in einer Komponente so oft verwendet werden, wie Sie möchten. Sie sollten children
(untergeordnete Elemente) zuerst verwenden, aber nicht zögern, auf Props zurückzugreifen, wenn das nicht ausreicht.
In diesem Schritt haben Sie gelernt, wie sich JSX- und React-Komponenten als Props an eine andere Komponente übergeben lassen. Dadurch erhält Ihre Komponente die Flexibilität, für viele Situationen einsetzbar zu sein, in denen eine Wrapper-Komponente mehrere Props zum Verwalten von JSX oder Komponenten benötigt.
Sie haben eine Vielzahl von Wrapping-Komponenten erstellt, die Daten flexibel anzeigen können, während eine vorhersehbare Optik und Struktur gewahrt bleiben. Sie haben Komponenten erstellt, die unbekannte Props aufnehmen und an verschachtelte Komponenten übergeben können. Außerdem haben Sie das native Prop children
verwendet, um Wrapper-Komponenten zu erstellen, die eine beliebige Anzahl von verschachtelten Elementen handhaben können. Abschließend haben Sie eine Komponente erstellt, die JSX- oder React-Komponenten als Prop nutzen können, damit Ihre Wrapper-Komponente mehrere Instanzen mit verschiedenen Anpassungen verarbeiten kann.
Wrapper-Komponenten bieten Ihnen die Möglichkeit, Anpassungen an unbekannte Umstände vorzunehmen sowie die Wiederverwendbarkeit und Konsistenz von Code zu maximieren. Dieses Muster ist nützlich zur Erstellung von grundlegenden UI-Elementen, die Sie in einer Anwendung häufiger wiederverwenden. Dazu gehören Schaltflächen, Warnmeldungen, modale Elemente, Diashows und mehr. Sie werden sehen, dass Sie immer wieder dahin zurückkehren werden.
Wenn Sie weitere React-Tutorials konsultieren möchten, sehen Sie sich unsere React-Themenseite an oder kehren Sie zurück zur Seite der Reihe Codieren in React.js.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!