Im vorherigen Kapitel haben Sie die Grundlagen von React-Komponenten kennengelernt. Sie verstehen jetzt, dass Komponenten JavaScript-Funktionen sind, die JSX zurückgeben. Diese Komponenten waren jedoch statisch – sie zeigten immer dieselben Inhalte an. In diesem Kapitel lernen Sie Props kennen, das Konzept, das Komponenten erst richtig mächtig und wiederverwendbar macht.
Props (kurz für “Properties”) sind der fundamentale Mechanismus in React, um Daten von einer Komponente an eine andere zu übertragen. Sie verwandeln statische Komponenten in dynamische, konfigurierbare Bausteine, die sich je nach übergebenen Daten unterschiedlich verhalten können.
Der beste Weg, Props zu verstehen, ist der Vergleich mit Funktionsparametern in der regulären JavaScript-Programmierung. Betrachten Sie diese normale JavaScript-Funktion:
function greetUser(name, age) {
return `Hallo ${name}, du bist ${age} Jahre alt!`;
}
greetUser("Anna", 25); // "Hallo Anna, du bist 25 Jahre alt!"
greetUser("Max", 30); // "Hallo Max, du bist 30 Jahre alt!"Eine React-Komponente mit Props funktioniert auf sehr ähnliche Weise:
function UserGreeting(props) {
return <h1>Hallo {props.name}, du bist {props.age} Jahre alt!</h1>;
}
// Verwendung:
<UserGreeting name="Anna" age={25} />
<UserGreeting name="Max" age={30} />Der entscheidende Unterschied liegt darin, dass React alle
übergebenen Attribute automatisch in einem Objekt namens
props sammelt und dieses als ersten Parameter an Ihre
Komponenten-Funktion übergibt.
Props können verschiedene Datentypen übertragen. Die Syntax unterscheidet sich je nach Typ:
String-Props werden wie HTML-Attribute übergeben:
<Welcome message="Herzlich willkommen!" />Numerische Props werden in geschweifte Klammern eingeschlossen:
<Counter startValue={10} />Boolean-Props können verkürzt geschrieben werden:
<Button disabled />
// Equivalent zu: <Button disabled={true} />Objekte und Arrays werden ebenfalls in geschweifte Klammern übergeben:
<UserCard user={{name: "Anna", email: "anna@example.com"}} />
<ProductList items={["Laptop", "Maus", "Tastatur"]} />Diese Flexibilität macht Props extrem vielseitig. Sie können nahezu jeden JavaScript-Wert als Prop übergeben, einschließlich Funktionen – ein Konzept, das in späteren Kapiteln für Event-Handling wichtig wird.
In professionellen React-Anwendungen hat sich TypeScript als Standard etabliert, da es Typsicherheit bietet und Entwicklungsfehler bereits zur Compile-Zeit erkennt. Für Props definieren Sie Interfaces, die genau beschreiben, welche Daten eine Komponente erwartet:
interface UserCardProps {
name: string;
age: number;
email: string;
isActive: boolean;
}
function UserCard(props: UserCardProps) {
return (
<div>
<h2>{props.name}</h2>
<p>Alter: {props.age}</p>
<p>Email: {props.email}</p>
<span>{props.isActive ? "Aktiv" : "Inaktiv"}</span>
</div>
);
}Diese Interface-Definition bietet mehrere Vorteile: Sie dokumentiert, welche Props die Komponente benötigt, verhindert Tippfehler bei Prop-Namen und ermöglicht exzellente IDE-Unterstützung mit Autocompletion und Fehlerprüfung.
Anstatt immer props.name, props.age zu
schreiben, können Sie JavaScript’s Destructuring-Syntax verwenden, um
direkt auf die gewünschten Properties zuzugreifen:
function UserCard({ name, age, email, isActive }: UserCardProps) {
return (
<div>
<h2>{name}</h2>
<p>Alter: {age}</p>
<p>Email: {email}</p>
<span>{isActive ? "Aktiv" : "Inaktiv"}</span>
</div>
);
}Diese Schreibweise ist nicht nur sauberer und lesbarer, sondern macht auch sofort klar, welche Props die Komponente tatsächlich verwendet. Sie ist in der React-Community zum Standard geworden.
Nicht alle Props müssen immer übergeben werden. Sie können Props als optional markieren und Standardwerte definieren:
interface ButtonProps {
text: string;
type?: 'primary' | 'secondary' | 'danger'; // Optional
disabled?: boolean; // Optional
}
function Button({ text, type = 'primary', disabled = false }: ButtonProps) {
return (
<button
className={`btn btn-${type}`}
disabled={disabled}
>
{text}
</button>
);
}
// Verwendung:
<Button text="Klicken" /> // Verwendet Standardwerte
<Button text="Löschen" type="danger" /> // Überschreibt type
<Button text="Laden" disabled={true} /> // Überschreibt disabledDas Fragezeichen nach dem Property-Namen (type?)
markiert es als optional. Die Standardwerte werden direkt in der
Destructuring-Syntax definiert.
Ein fundamentales Prinzip von React ist der unidirektionale Datenfluss: Props fließen immer von Eltern-Komponenten zu Kind-Komponenten, niemals umgekehrt. Dieses Prinzip hat wichtige Auswirkungen:
Props sind read-only: Eine Komponente darf ihre Props niemals direkt verändern. Props sind unveränderlich aus Sicht der empfangenden Komponente.
Vorhersagbarer Datenfluss: Da Daten nur in eine Richtung fließen, ist es einfacher zu verstehen, woher Daten kommen und wie Änderungen propagiert werden.
Einfachere Fehlersuche: Wenn ein Wert falsch ist, müssen Sie nur “nach oben” schauen, um die Quelle zu finden.
Betrachten Sie diese Hierarchie:
function App() {
const user = { name: "Anna", role: "Admin" };
return (
<div>
<Header user={user} />
<MainContent user={user} />
</div>
);
}
function Header({ user }) {
return <Navigation userName={user.name} userRole={user.role} />;
}
function Navigation({ userName, userRole }) {
return (
<nav>
<span>Willkommen, {userName}</span>
{userRole === "Admin" && <AdminPanel />}
</nav>
);
}Die Daten fließen von App über Header zu
Navigation. Jede Komponente kann entscheiden, welche Props
sie an ihre Kinder weitergibt.
In professionellen Anwendungen ist es wichtig, mit unerwarteten oder fehlenden Props umzugehen:
interface ProductProps {
name: string;
price?: number;
description?: string;
}
function Product({ name, price, description }: ProductProps) {
// Defensive Programmierung: Was passiert, wenn Props fehlen?
if (!name) {
return <div>Fehler: Produktname ist erforderlich</div>;
}
return (
<div>
<h3>{name}</h3>
{price && <p>Preis: €{price.toFixed(2)}</p>}
{description && <p>{description}</p>}
</div>
);
}TypeScript hilft dabei, viele Probleme zur Compile-Zeit zu erkennen, aber eine defensive Programmierung in der Komponente selbst macht Ihre Anwendung robuster.
Props können komplexe Datenstrukturen übertragen. Dies ist besonders nützlich für Komponenten, die strukturierte Daten anzeigen:
interface UserData {
id: number;
name: string;
email: string;
preferences: {
theme: 'light' | 'dark';
notifications: boolean;
};
}
interface UserProfileProps {
user: UserData;
actions: string[];
}
function UserProfile({ user, actions }: UserProfileProps) {
return (
<div>
<h2>{user.name}</h2>
<p>{user.email}</p>
<p>Theme: {user.preferences.theme}</p>
<div>
<h3>Verfügbare Aktionen:</h3>
{actions.map(action => (
<button key={action}>{action}</button>
))}
</div>
</div>
);
}Beachten Sie, wie wir sowohl verschachtelte Objekte
(user.preferences.theme) als auch Arrays
(actions.map()) verwenden können.
Obwohl Props mächtig sind, sollten Sie einige Performance-Aspekte beachten:
Vermeiden Sie inline Objekte: Jedes Mal, wenn eine Komponente rendert, werden inline definierte Objekte neu erstellt:
// Schlecht: Neues Objekt bei jedem Render
<UserCard style={{color: 'red', fontSize: '14px'}} />
// Besser: Objekt außerhalb definieren
const cardStyle = {color: 'red', fontSize: '14px'};
<UserCard style={cardStyle} />Props-Drilling vermeiden: Wenn Sie Props durch viele Komponenten-Ebenen hindurch reichen müssen, deutet dies auf ein Architekturproblem hin. Spätere Kapitel werden Lösungen wie Context API behandeln.
Props mutieren: Props sind read-only. Versuchen Sie
niemals, props.value = newValue zu schreiben.
Falsche Prop-Namen: Achten Sie auf korrekte
Groß-/Kleinschreibung. userName und username
sind verschiedene Props.
Vergessene geschweiften Klammern: Numerische und
Boolean-Werte müssen in geschweiften Klammern stehen:
<Counter value={10} />, nicht
<Counter value="10" />.
TypeScript-Interfaces ignorieren: Definieren Sie immer Interfaces für Ihre Props. Es spart Zeit beim Debugging und verbessert die Code-Qualität erheblich.
Schauen Sie sich an, wie Props in einer realistischen Komponente zusammenwirken:
interface ArticleProps {
title: string;
author: string;
publishDate: Date;
content: string;
tags: string[];
featured?: boolean;
}
function Article({
title,
author,
publishDate,
content,
tags,
featured = false
}: ArticleProps) {
const formatDate = (date: Date) => {
return date.toLocaleDateString('de-DE', {
year: 'numeric',
month: 'long',
day: 'numeric'
});
};
return (
<article className={featured ? 'article featured' : 'article'}>
<header>
<h1>{title}</h1>
<p>Von {author} am {formatDate(publishDate)}</p>
</header>
<main>
<p>{content}</p>
</main>
<footer>
<div className="tags">
{tags.map(tag => (
<span key={tag} className="tag">#{tag}</span>
))}
</div>
</footer>
</article>
);
}Diese Komponente demonstriert viele Props-Konzepte: verschiedene Datentypen, optionale Props mit Standardwerten, Array-Verarbeitung und bedingte Darstellung.
Props ermöglichen es, Daten in Komponenten hineinzubekommen, aber sie sind read-only. Für interaktive Anwendungen benötigen Sie einen Weg, um Daten zu ändern und auf Benutzerinteraktionen zu reagieren.
In den kommenden Kapiteln werden wir Event-Handling betrachten, um zu verstehen, wie Komponenten auf Klicks und andere Benutzeraktionen reagieren können. Anschließend führen wir State ein, das Konzept für veränderbare Daten innerhalb von Komponenten. Props und State zusammen bilden das Fundament für jede React-Anwendung.
Zunächst aber vertiefen Sie Ihr Verständnis von Props durch praktische Übungen. Experimentieren Sie mit verschiedenen Datentypen, erstellen Sie wiederverwendbare Komponenten und beobachten Sie, wie Props den Charakter Ihrer Komponenten völlig verändern können. Props sind der Schlüssel zur Komponentenkomposition – der Kunst, große Anwendungen aus kleinen, fokussierten Bausteinen zusammenzusetzen.