Zum Inhalt springen
aviral gupta

// B2.3 · ca. 30 Min. · Einstieg

Props und children

Nach dieser Lektion übergeben und lesen Sie eigene Props, geben ihnen Standardwerte, reichen sie mit Spread weiter und umschließen Inhalt mit children.

Lektion 3 von 6 in B2 Die Oberfläche beschreiben

Danach können Sie

  • Eigene Props übergeben und sie per Destrukturierung oder als props.name lesen
  • Einem Prop einen Standardwert geben und alle Props mit {...props} weiterreichen
  • Verschachteltes JSX mit children umschließen und Props als schreibgeschützt behandeln
  1. Aufwärmen · Aufgabe 1 von 7

    Zum Aufwärmen aus Lektion B2.2: geschweifte Klammern und ein Style-Objekt. Welchen Text zeigt Badge?

    const person = {
      name: 'Hedy Lamarr',
      theme: { color: 'pink' }
    };
    
    function Badge() {
      return <p style={person.theme}>{person.name}'s badge</p>;
    }
  2. Vorhersagen · Aufgabe 2 von 7

    Sagen Sie voraus, bevor Sie weiterlesen. App verschachtelt einen Absatz in <Card>. Welchen Text zeigt App?

    function Card({ title }) {
      return (
        <section>
          <h2>{title}</h2>
        </section>
      );
    }
    
    function App() {
      return (
        <Card title="Notes">
          <p>Buy milk</p>
        </Card>
      );
    }
  3. Üben · Aufgabe 3 von 7

    Füllen Sie die Lücke so, dass das Bild 100 Pixel breit ist, wenn die Eltern keine Größe übergeben.

    function Avatar({ name, ____ }) {
      return <img alt={name} width={size} />;
    }
    function Avatar({ name, }) {
  4. Üben · Aufgabe 4 von 7

    Ordnen Sie jedem Stück Code zu, was es tut.

  5. Üben · Aufgabe 5 von 7

    Profile reicht seine Props mit Spread weiter. Welchen Text zeigt App?

    function Avatar({ name, size }) {
      return <p>{name} ({size})</p>;
    }
    
    function Profile(props) {
      return <Avatar {...props} />;
    }
    
    function App() {
      return <Profile name="Lin" size={80} />;
    }
  6. Denksport · Aufgabe 6 von 7

    Knobelaufgabe. Avatar hat die Standardgröße 100, und App übergibt size={null} (Ergebnis auf Englisch: nothing = nichts). Welchen Text zeigt App?

    function Avatar({ size = 100 }) {
      return <p>{size}</p>;
    }
    
    function App() {
      return <Avatar size={null} />;
    }
  7. Anwenden · Aufgabe 7 von 7

    Mini-Aufgabe: eine Box mit Abzeichen. Schreiben Sie in main.jsx eine Komponente Badge mit den Props label und color, wobei color standardmäßig gray ist, und eine Komponente Box mit einem Prop heading, die ihre children unter der Überschrift rendert. Der Default-Export rendert eine Box mit zwei Badges (eines mit Farbe, eines ohne) und einem Absatz darin. Führen Sie es aus und prüfen Sie, dass das zweite Badge grau ist und der Absatz erscheint.

    Prüfen Sie Ihr Ergebnis anhand dieser Liste

Selbst programmieren

Lesen Sie das ausgearbeitete Beispiel und lösen Sie dann die Übungen. Ihr Code läuft in Ihrem Browser oder auf Ihrem Computer und wird nie hochgeladen.

Ausgearbeitetes Beispiel

Eine Karte, die einen Avatar umschließt

Card hat ein Prop title und rendert über children, was darin verschachtelt ist. Avatar liest ein Objekt person und eine Größe, mit size = 100 als Standardwert. Die erste Karte gibt keine Größe an, also gilt der Standardwert; die zweite übergibt size={50} und verschachtelt nach dem Avatar einen Absatz. Die Bilder laden im Runner nicht; der Snapshot zeigt die Attribute, die React geschrieben hat.

main.jsx

function Avatar({ person, size = 100 }) {
  return (
    <img
      className="avatar"
      src={person.imageUrl}
      alt={person.name}
      width={size}
      height={size}
    />
  );
}

function Card({ title, children }) {
  return (
    <section className="card">
      <h2>{title}</h2>
      {children}
    </section>
  );
}

export default function Profile() {
  return (
    <div>
      <Card title="Default size">
        <Avatar person={{ name: 'Katsuko Saruhashi', imageUrl: 'katsuko.jpg' }} />
      </Card>
      <Card title="Size 50, with a note">
        <Avatar person={{ name: 'Aklilu Lemma', imageUrl: 'aklilu.jpg' }} size={50} />
        <p>Card shows whatever you nest inside it.</p>
      </Card>
    </div>
  );
}

Ausführen mit

npm run dev

Ausgabe

<!-- #root -->
<div id="root"><div><section class="card"><h2>Default size</h2><img class="avatar" alt="Katsuko Saruhashi" width="100" height="100" src="katsuko.jpg"></section><section class="card"><h2>Size 50, with a note</h2><img class="avatar" alt="Aklilu Lemma" width="50" height="50" src="aklilu.jpg"><p>Card shows whatever you nest inside it.</p></section></div></div>
  • Der erste Avatar bekam keine Größe, also galt size = 100: width="100" height="100".
  • Die zweite Karte bekam zwei children, den Avatar und den Absatz, und renderte beide dort, wo sie {children} schreibt.
  • Card weiß nicht, was es umschließt: Dieselbe Komponente hält ein Bild oder ein Bild und eine Notiz.
  • Jede Karte rendert ihr eigenes Prop title über ihren children.
Ändern und ausführen

Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.

Beim ersten Ausführen lädt Ihr Browser React und den Compiler herunter, der JSX in JavaScript übersetzt (bis zu 2 MB), und speichert beides im Cache. Ihre Komponenten laufen in Ihrem Browser und bleiben auf Ihrem Gerät.

Ihre Seite

Ihre Seite läuft in einem abgeschotteten Rahmen. Sie hat keinen Zugriff auf diese Website, und ihr localStorage liegt nur für diesen Lauf im Speicher: Der nächste Lauf beginnt leer.

Führen Sie das Programm aus, um seine Seite hier zu sehen.

Übungen

Übung 1 von 2

Ein Panel, das seinen Inhalt umschließt

Panel zeigt einen Titel, aber die darin verschachtelten Absätze erscheinen nie, und das zweite Panel hat eine leere Überschrift. Lassen Sie Panel seine children unter der Überschrift rendern, und geben Sie title den Standardwert Notes. Behalten Sie den Namen Panel und seinen Export: Die Tests rendern <Panel> mit eigenen children.

Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.

Beim ersten Ausführen lädt Ihr Browser React und den Compiler herunter, der JSX in JavaScript übersetzt (bis zu 2 MB), und speichert beides im Cache. Ihre Komponenten laufen in Ihrem Browser und bleiben auf Ihrem Gerät.

Ihre Seite

Ihre Seite läuft in einem abgeschotteten Rahmen. Sie hat keinen Zugriff auf diese Website, und ihr localStorage liegt nur für diesen Lauf im Speicher: Der nächste Lauf beginnt leer.

Führen Sie das Programm aus, um seine Seite hier zu sehen.

Hinweise
  1. Hinweis 1

    Verschachteltes JSX kommt als Prop namens children an. Nehmen Sie es neben title in die Destrukturierung auf.

  2. Hinweis 2

    Setzen Sie {children} in die <section>, hinter das <h2>.

  3. Hinweis 3

    Ein Standardwert gehört in die Destrukturierung: { title = 'Notes', children }.

Eine Lösung zeigen

Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.

export function Panel({ title = 'Notes', children }) {
  return (
    <section className="panel">
      <h2>{title}</h2>
      {children}
    </section>
  );
}

export default function App() {
  return (
    <>
      <Panel title="Packing">
        <p>Bring a helmet</p>
      </Panel>
      <Panel>
        <p>Water the plants</p>
      </Panel>
    </>
  );
}
Auf dem eigenen Computer ausführen

Installieren Sie React 19.3 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.

main.jsx

// Panel should show what is nested inside it, and the title Notes
// when no title is given.
export function Panel({ title }) {
  return (
    <section className="panel">
      <h2>{title}</h2>
    </section>
  );
}

export default function App() {
  return (
    <>
      <Panel title="Packing">
        <p>Bring a helmet</p>
      </Panel>
      <Panel>
        <p>Water the plants</p>
      </Panel>
    </>
  );
}

main.test.jsx

import {test} from 'node:test';
import assert from 'node:assert/strict';
import {render, screen} from '@testing-library/react';
import App, {Panel} from './main.jsx';

test('Panel zeigt das darin verschachtelte JSX', () => {
  render(<Panel title="Tools"><button>Inside</button></Panel>);
  assert.ok(screen.queryByRole('button', {name: 'Inside'}), 'der in <Panel> verschachtelte Button ist nicht auf der Seite');
});

test('Ein Panel ohne title zeigt den Titel Notes', () => {
  render(<Panel><p>Hello</p></Panel>);
  const heading = screen.getByRole('heading', {level: 2}).textContent;
  assert.equal(heading, 'Notes', 'die Überschrift lautet ' + JSON.stringify(heading));
});

test('Ein übergebener title wird gezeigt', () => {
  render(<Panel title="Packing"><p>Hello</p></Panel>);
  const heading = screen.getByRole('heading', {level: 2}).textContent;
  assert.equal(heading, 'Packing', 'die Überschrift lautet ' + JSON.stringify(heading));
});

test('App zeigt beide Panels mit ihrem Inhalt', () => {
  render(<App />);
  const headings = screen.getAllByRole('heading', {level: 2}).map((h) => h.textContent);
  assert.deepEqual(headings, ['Packing', 'Notes'], 'die Überschriften sind ' + JSON.stringify(headings));
  assert.ok(screen.queryByText('Water the plants'), 'der Text Water the plants ist nicht auf der Seite');
});

Legen Sie main.jsx in einem Vite-React-Projekt (npm create vite@latest, Vorlage react) als App.jsx in src/ ab und starten Sie es mit npm run dev. React rendert es dort wie hier in <StrictMode>.

Programm ausführen:

npm run dev

Für die Prüfungen gibt es noch keinen Befehl auf Ihrem Computer. Sie stehen in main.test.jsx, geschrieben mit node:test und React Testing Library.

Übung 2 von 2

Props an einen Avatar weiterreichen

Gallery übergibt Profile ein person-Objekt und manchmal eine Größe, aber Profile reicht nur person weiter, deshalb hat kein Bild eine Breite. Lassen Sie Profile jedes Prop, das es bekommt, mit der Spread-Syntax an Avatar weiterreichen, und geben Sie Avatar die Standardgröße 60. Eine Größe von 0 muss 0 bleiben. Die Bilder laden im Runner nicht; die Tests prüfen die Attribute.

Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.

Beim ersten Ausführen lädt Ihr Browser React und den Compiler herunter, der JSX in JavaScript übersetzt (bis zu 2 MB), und speichert beides im Cache. Ihre Komponenten laufen in Ihrem Browser und bleiben auf Ihrem Gerät.

Ihre Seite

Ihre Seite läuft in einem abgeschotteten Rahmen. Sie hat keinen Zugriff auf diese Website, und ihr localStorage liegt nur für diesen Lauf im Speicher: Der nächste Lauf beginnt leer.

Führen Sie das Programm aus, um seine Seite hier zu sehen.

Hinweise
  1. Hinweis 1

    Führen Sie es zuerst aus: Die <img>-Elemente haben keine Breite, weil size nie bei Avatar ankommt.

  2. Hinweis 2

    Nehmen Sie das ganze props-Objekt, function Profile(props), und rendern Sie <Avatar {...props} />.

  3. Hinweis 3

    Schreiben Sie den Standardwert in die Destrukturierung von Avatar, size = 60. size || 60 würde auch 0 ersetzen, was ein Test bemerkt.

Eine Lösung zeigen

Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.

function Avatar({ person, size = 60 }) {
  return (
    <img
      className="avatar"
      src={person.imageUrl}
      alt={person.name}
      width={size}
      height={size}
    />
  );
}

export function Profile(props) {
  return (
    <div className="card">
      <Avatar {...props} />
    </div>
  );
}

export default function Gallery() {
  return (
    <>
      <Profile person={{ name: 'Lin Lanying', imageUrl: 'lin.jpg' }} size={80} />
      <Profile person={{ name: 'Aklilu Lemma', imageUrl: 'aklilu.jpg' }} />
    </>
  );
}
Auf dem eigenen Computer ausführen

Installieren Sie React 19.3 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.

main.jsx

function Avatar({ person, size }) {
  return (
    <img
      className="avatar"
      src={person.imageUrl}
      alt={person.name}
      width={size}
      height={size}
    />
  );
}

// TODO: Avatar's size is 60 when none is given, and Profile passes
// every prop it gets on to Avatar.
export function Profile({ person }) {
  return (
    <div className="card">
      <Avatar person={person} />
    </div>
  );
}

export default function Gallery() {
  return (
    <>
      <Profile person={{ name: 'Lin Lanying', imageUrl: 'lin.jpg' }} size={80} />
      <Profile person={{ name: 'Aklilu Lemma', imageUrl: 'aklilu.jpg' }} />
    </>
  );
}

main.test.jsx

import {test} from 'node:test';
import assert from 'node:assert/strict';
import {render, screen} from '@testing-library/react';
import Gallery, {Profile} from './main.jsx';

test('Lin Lanying ist 80 Pixel breit, wie Gallery es übergibt', () => {
  render(<Gallery />);
  const width = screen.getByRole('img', {name: 'Lin Lanying'}).getAttribute('width');
  assert.equal(width, '80', 'das Bild hat width=' + JSON.stringify(width));
});

test('Aklilu Lemma bekommt die Standardgröße 60', () => {
  render(<Gallery />);
  const img = screen.getByRole('img', {name: 'Aklilu Lemma'});
  assert.equal(img.getAttribute('width'), '60', 'das Bild hat width=' + JSON.stringify(img.getAttribute('width')));
  assert.equal(img.getAttribute('height'), '60', 'das Bild hat height=' + JSON.stringify(img.getAttribute('height')));
});

test('Profile gibt jede Größe und das Bild weiter', () => {
  render(<Profile person={{ name: 'Ada', imageUrl: 'ada.jpg' }} size={40} />);
  const img = screen.getByRole('img', {name: 'Ada'});
  assert.equal(img.getAttribute('width'), '40', 'das Bild hat width=' + JSON.stringify(img.getAttribute('width')));
  assert.equal(img.getAttribute('src'), 'ada.jpg', 'das Bild hat src=' + JSON.stringify(img.getAttribute('src')));
});

test('size={0} wird weitergegeben, nicht durch den Standardwert ersetzt', () => {
  render(<Profile person={{ name: 'Ada', imageUrl: 'ada.jpg' }} size={0} />);
  const width = screen.getByRole('img', {name: 'Ada'}).getAttribute('width');
  assert.equal(width, '0', 'das Bild hat width=' + JSON.stringify(width));
});

Legen Sie main.jsx in einem Vite-React-Projekt (npm create vite@latest, Vorlage react) als App.jsx in src/ ab und starten Sie es mit npm run dev. React rendert es dort wie hier in <StrictMode>.

Programm ausführen:

npm run dev

Für die Prüfungen gibt es noch keinen Befehl auf Ihrem Computer. Sie stehen in main.test.jsx, geschrieben mit node:test und React Testing Library.

Häufige Fehler

Ein Prop in der Komponente ändern

function Avatar(props) {
  props.size = props.size * 2;
  return <img alt="Lin Lanying" width={props.size} />;
}

export default function Profile() {
  return <Avatar size={50} />;
}

Was React ausgibt

TypeError: Cannot assign to read only property 'size' of object '#<Object>'

Warum, und die Lösung

Props sind schreibgeschützt. In der Entwicklung friert React das props-Objekt ein, deshalb wirft die Zuweisung, und der Lauf gibt Uncaught TypeError aus (Formulierung von Chrome und Node.js; Firefox und Safari formulieren es anders). Berechnen Sie stattdessen einen neuen Wert: const shown = props.size * 2, und verwenden Sie width={shown}. Muss sich die Größe selbst ändern, übergeben die Eltern eine andere.

Props ohne die drei Punkte weiterreichen

function Avatar({ size }) {
  return <img alt="Lin Lanying" width={size} />;
}

export default function Profile(props) {
  return <Avatar {props} />;
}

Was React ausgibt

error TS1005: '...' expected.

Warum, und die Lösung

Klammern in der Attributliste eines Tags müssen einen Spread enthalten, deshalb bricht die JSX-Umwandlung ab, und nichts läuft. Die ganze Zeile beginnt mit der Position, main.jsx(6,19). Schreiben Sie <Avatar {...props} /> oder übergeben Sie die Props einzeln: size={props.size}.

props.children nach dem Destrukturieren lesen

function Card({ title }) {
  return (
    <section className="card">
      <h2>{title}</h2>
      {props.children}
    </section>
  );
}

export default function App() {
  return (
    <Card title="Notes">
      <p>Buy milk</p>
    </Card>
  );
}

Was React ausgibt

ReferenceError: props is not defined

Warum, und die Lösung

Mit einer Destrukturierung in den Klammern gibt es keine Variable namens props: Es existiert nur title. Nehmen Sie children in die Destrukturierung auf, function Card({ title, children }), und schreiben Sie {children}. Oder behalten Sie das ganze Objekt, function Card(props), und verwenden Sie props.title und props.children.

React im Browser: React 19.3.0 (Entwicklungs-Build) und React Testing Library, MIT, von dieser Website ausgeliefert; JSX übersetzt TypeScript 6.0.3, Apache-2.0. Lizenz und Quellcode

Abschlussquiz

5 Fragen, ohne Hinweise. Ab 80 % ist die Lektion abgeschlossen.

Erledigen Sie zuerst alle Aufgaben oben, um das Abschlussquiz freizuschalten.

Problem melden

Etwas ist falsch oder unklar? Beschreiben Sie es kurz, dann wird es geprüft und korrigiert.

#

Mindestens 20 Zeichen.

Nur, wenn Sie eine Antwort wünschen.

Kernideen

Props sind das eine Argument einer Komponente

Props an eingebaute Tags übergeben Sie schon: className, src, alt, width und height an einem <img>. Deren Namen legt HTML fest. Ihre eigenen Komponenten nehmen beliebige Props, die Sie wählen: <Avatar person={lin} size={100} />. React ruft die Komponente mit einem Argument auf, einem Objekt mit allen Props. Sie können es ganz behalten, function Avatar(props), und props.size lesen, oder es destrukturieren, function Avatar({ person, size }), und size wie eine Variable verwenden. Beides liest dasselbe Objekt; Destrukturieren ist der übliche Stil, weil man das ganze Objekt selten braucht.

Standardwerte und Weiterreichen mit Spread

Schreiben Sie in der Destrukturierung = und einen Wert hinter ein Prop: function Avatar({ person, size = 100 }). Der Standardwert gilt, wenn das Prop size fehlt oder undefined ist. size={null} und size={0} sind Werte, also entfällt der Standardwert: null zeigt nichts, 0 wird angezeigt. Eine Komponente, die alle ihre Props weitergibt, kann sie mit der JSX-Spread-Syntax weiterreichen: <Avatar {...props} />. react.dev rät, Spread sparsam einzusetzen; Props einzeln zu nennen ist oft klarer, und viele Hüllen schreibt man besser mit children.

children, und Props, die Sie nie ändern

JSX, das in einem Tag verschachtelt ist, <Card><Avatar /></Card>, kommt bei Card als Prop namens children an. Card entscheidet, wo es hinkommt: <div className="card">{children}</div>. Rendert Card children nicht, erscheint das verschachtelte JSX einfach nicht, ohne Warnung. Props können sich von Render zu Render unterscheiden, aber jeder Render bekommt ein neues, schreibgeschütztes props-Objekt. In der Entwicklung friert React es ein, deshalb wirft props.size = 5 einen TypeError. Um etwas anderes zu zeigen, bittet eine Komponente ihre Eltern um andere Props; mit State, den Sie aus B1.3 kennen, merken sich die Eltern sie.

Quellen

Zuletzt geprüft am 5. Oktober 2026