Menu

React children Prop: Wrapper-Komponenten und Slots

children ist die Prop, die alles enthält, was du zwischen das öffnende und das schließende Tag einer Komponente schreibst. Lerne, wie du damit Wrapper- und Layout-Komponenten baust, mehrere Slots als benannte Props übergibst, children als Funktion nutzt und wann die Children-API das falsche Werkzeug ist.

Diese Seite enthält ausführbare Editoren - bearbeiten, ausführen und Ausgabe sofort sehen.

In React ist children die Prop, die alles enthält, was du zwischen das öffnende und das schließende Tag einer Komponente schreibst. Eine Komponente, die {children} irgendwo in ihrer Ausgabe rendert, wird zum Wrapper: Sie liefert den Rahmen, und der Aufrufer liefert den Inhalt.

Beide Karten teilen sich einen Rahmen, ein Padding und einen Stil für die Überschrift, aber jede enthält völlig anderen Inhalt. Füge eine dritte <Card title="Help"> mit einem Link darin hinzu, und sie bekommt denselben Rahmen geschenkt.

Wie children zur Komponente gelangt

JSX macht aus verschachteltem Inhalt eine Prop. Diese beiden Zeilen erzeugen dasselbe Element:

<Card title="Profile"><p>Ada</p></Card>

<Card title="Profile" children={<p>Ada</p>} />

children ist also eine gewöhnliche Prop mit einer besonderen Art der Übergabe. Du destrukturierst sie wie jede andere (function Card({ children })) oder liest sie als props.children. Die Seite zu Props behandelt Props allgemein.

Was in children ankommt, hängt davon ab, was du zwischen die Tags geschrieben hast. Ein Kind kommt als genau dieses Kind an. Mehrere Kinder kommen als Array an. Text kommt als String an, und gar nichts kommt als undefined an.

Die Konsole zeigt object, array of 2, string und undefined. Darum musst du dich selten kümmern: {children} zu rendern funktioniert mit all dem, und null, undefined, true und false rendern nichts. Die Form ist nur wichtig, wenn du children untersuchen oder ändern willst, und genau davor warnt der letzte Abschnitt.

Layout-Komponenten

Die häufigste Verwendung von children ist eine Layout-Komponente: ein Seitengerüst, ein Layout mit Seitenleiste, eine zentrierte Spalte. Die Komponente besitzt Struktur und Abstände, und jede Seite, die sie nutzt, übergibt ihren eigenen Inhalt.

function PageLayout({ children }) {
    return (
        <div className="page">
            <Header />
            <main className="page-content">{children}</main>
            <Footer />
        </div>
    );
}

function AboutPage() {
    return (
        <PageLayout>
            <h1>About us</h1>
            <p>We teach people to code.</p>
        </PageLayout>
    );
}

PageLayout weiß nicht und muss nicht wissen, was eine Über-uns-Seite enthält. Diese Trennung ist der Sinn: Ändere den Header einmal, und jede Seite in diesem Layout übernimmt ihn.

Mehrere Slots mit benannten Props

children ist ein Slot. Wenn eine Komponente Inhalt an mehr als einer Stelle braucht, übergib die zusätzlichen Teile als benannte Props. Jede Prop kann JSX enthalten, also kann ein Modal einen title, einen footer und seinen Inhalt als children annehmen.

Das Gerüst des Modals steuert Rahmen, Padding und Reihenfolge der drei Bereiche, und der Aufrufer füllt jeden davon. Andere Frameworks nennen das Slots; in React sind es einfach Props. Das <>...</> um die beiden Buttons ist ein Fragment, das sie gruppiert, ohne ein zusätzliches Element hinzuzufügen. Ein echter Dialog würde außerdem mit einem Portal in document.body rendern, damit er über der Seite liegt.

Verschiebe das <p> in die Prop title, und der Text erscheint im Header: Die Komponente entscheidet, wohin jede Prop kommt, der Aufrufer entscheidet nur, was hineinkommt.

children als Funktion

Manchmal besitzt der Wrapper State, und der Aufrufer soll entscheiden, wie er dargestellt wird. Statt eines Elements übergibt der Aufrufer eine Funktion als children, und der Wrapper ruft sie mit den Werten auf. Dieses Muster heißt Render Prop.

Ein Toggle zeichnet einen Button, der andere eine Checkbox, aus derselben Logik. Render Props waren vor Hooks der wichtigste Weg, zustandsbehaftete Logik zu teilen. Heute liest sich ein Custom Hook wie useToggle() meist besser, aber in Bibliotheken für Listen, Formulare und Animationen wirst du Render Props weiterhin sehen.

Die Children-API und cloneElement

React exportiert ein Objekt Children mit Helfern zum Durchlaufen von children: Children.map, Children.forEach, Children.count, Children.toArray und Children.only. Zusammen mit cloneElement, das ein Element mit neuen Props kopiert, kann ein Elternteil damit untersuchen und ändern, was es bekommen hat. Das React-Team führt sie als Legacy-APIs: Sie funktionieren noch, aber neuer Code sollte sie meiden.

Der Grund ist, dass sie nur die Elemente sehen, die direkt zwischen den Tags stehen. Sie sehen nicht, was diese Elemente rendern.

Die Liste zeigt vier Einträge, aber die Konsole sagt Children.count = 3, weil TwoMore ein Kind ist, egal wie viele Einträge es rendert. cloneElement gibt die Prop style außerdem an TwoMore, das sie ignoriert, also sind der dritte und vierte Eintrag nicht gestreift. Wer ein paar <li>-Elemente in eine Komponente auslagert, macht das Elternteil kaputt, ohne es anzufassen.

Die Lösung ist, nicht mehr in children hineinzugreifen und stattdessen Daten zu übergeben:

function NumberedList({ items }) {
    return (
        <ol>
            {items.map((item, i) => (
                <li key={item.id} style={{ color: i % 2 ? 'gray' : 'black' }}>
                    {item.label}
                </li>
            ))}
        </ol>
    );
}

Jetzt rendert die Liste jede Zeile selbst, und nichts hängt davon ab, wie der Aufrufer sein JSX geschrieben hat. Wenn ein Elternteil Werte mit tief verschachtelten Kindern teilen muss (ein ausgewählter Tab, ein Theme), nutze Context, statt Props auf sie zu klonen.

children in TypeScript typisieren

In TypeScript typisierst du children als React.ReactNode. Das deckt alles ab, was React rendern kann: Elemente, Strings, Zahlen, Arrays davon, null, undefined und Booleans.

import type { ReactNode } from 'react';

type CardProps = {
    title: string;
    children: ReactNode;
};

function Card({ title, children }: CardProps) {
    return (
        <section>
            <h3>{title}</h3>
            {children}
        </section>
    );
}

Eine Render Prop typisierst du als die Funktion, die sie ist: children: (on: boolean, toggle: () => void) => ReactNode. Mach children optional (children?: ReactNode), wenn die Komponente auch leer sinnvoll ist.

Typische Fehler

Vergessen, children zu rendern. Wenn eine Komponente children annimmt, aber {children} nie in ihre Ausgabe setzt, verschwindet der Inhalt stillschweigend. Nichts warnt dich.

children wie eine Funktion aufrufen, obwohl es keine ist. children() funktioniert nur, wenn der Aufrufer eine Funktion übergeben hat. Wenn eine Komponente eine Render Prop erwartet, sag das in ihrem Namen oder ihrer Doku, oder nimm eine benannte Prop wie render an, damit die Absicht klar ist.

children mutieren. Elemente sind schreibgeschützt. React friert sie in der Entwicklung ein, also wirft eine Zuweisung an children.props dort einen Fehler. Erzeuge stattdessen eine neue Ausgabe.

Häufig gestellte Fragen

Was ist props.children in React?

Es ist der Inhalt zwischen dem öffnenden und dem schließenden Tag einer Komponente. In <Card><p>Hi</p></Card> erhält die Funktion Card das <p> als props.children und entscheidet, wo sie es rendert.

Ist children eine besondere Prop?

Nur in der Art, wie du sie übergibst. JSX legt den verschachtelten Inhalt in eine Prop namens children, aber in der Komponente ist sie eine gewöhnliche Prop. Du kannst sie auch explizit übergeben, wie in <Card children={<p>Hi</p>} />, und es funktioniert genauso.

Wie übergebe ich einer Komponente mehr als einen Inhaltsblock?

Nutze benannte Props für die zusätzlichen Blöcke. Eine Prop kann JSX enthalten wie children auch, also gibt <Modal title={<h2>Delete?</h2>} footer={<button>OK</button>}>Body</Modal> der Komponente drei Slots.

Sollte ich Children.map und cloneElement verwenden?

Vermeide sie in neuem Code. Sie sehen nur die Elemente, die direkt zwischen den Tags stehen, nicht das, was diese Elemente rendern, also brechen sie, sobald jemand ein Kind in eine andere Komponente packt. Übergib stattdessen ein Array mit Daten als Prop oder nutze Context.

Welchen Typ hat children in TypeScript?

Nutze React.ReactNode. Er deckt alles ab, was React rendern kann: Elemente, Strings, Zahlen, Arrays, null, undefined und Booleans.

Illustration der Programmiersprachen bei Coddy

Lerne mit Coddy zu programmieren

LOS GEHT'S