Zum Inhalt springen
aviral gupta

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

State zwischen Komponenten teilen

Nach dieser Lektion können Sie zwei Komponenten gemeinsam ändern lassen: Ihr State wandert in einen gemeinsamen Elternteil, der ihn samt Handlern weitergibt.

Lektion 3 von 6 in B5 State verwalten

Danach können Sie

  • State, den zwei Komponenten teilen, in ihren nächsten gemeinsamen Elternteil anheben und als Props weitergeben
  • Event-Handler weitergeben, damit Kinder den Elternteil bitten können, seinen State zu ändern
  • Kontrollierte von unkontrollierten Komponenten unterscheiden und für jedes Stück State einen Besitzer festlegen
  1. Aufwärmen · Aufgabe 1 von 7

    Zum Aufwärmen aus Lektion B5.2: einen Index halten, keine Kopie. Sie klicken einmal auf den dritten Button. Was zeigen die Buttons?

    function Planets() {
      const planets = ['Mercury', 'Venus', 'Earth'];
      const [selectedIndex, setSelectedIndex] = useState(0);
    
      return (
        <>
          {planets.map((name, index) => (
            <button key={name} onClick={() => setSelectedIndex(index)}>
              {index === selectedIndex ? '> ' + name : name}
            </button>
          ))}
        </>
      );
    }
  2. Vorhersagen · Aufgabe 2 von 7

    Sagen Sie voraus, bevor Sie weiterlesen. Jedes Panel hält seinen eigenen State isActive. Sie klicken auf Show in Hours, dann auf Show in Address. Welche Panels sind offen?

    function Panel({ title, children }) {
      const [isActive, setIsActive] = useState(false);
      return (
        <section>
          <h3>{title}</h3>
          {isActive ? <p>{children}</p> : <button onClick={() => setIsActive(true)}>Show</button>}
        </section>
      );
    }
    
    function Accordion() {
      return (
        <>
          <Panel title="Hours">Open daily from 8 to 18.</Panel>
          <Panel title="Address">Mill Lane 4, near the station.</Panel>
        </>
      );
    }
  3. Üben · Aufgabe 3 von 7

    Accordion hält const [activeIndex, setActiveIndex] = useState(0);. Ergänzen Sie die Funktion, die onShow des zweiten Panels aufruft, damit sein Show-Button es öffnet.

    <Panel title="Address" isActive={activeIndex === 1} onShow={() => ____(1)}>
    <Panel title="Address" isActive={activeIndex === 1} onShow={() => (1)}>
  4. Üben · Aufgabe 4 von 7

    Ordnen Sie jedem Begriff zu, was er in dieser Lektion bedeutet.

  5. Üben · Aufgabe 5 von 7

    Jetzt besitzt Accordion activeIndex. Sie klicken auf Show in Address, dann auf Show in Hours. Welche Panels sind offen?

    function Panel({ title, children, isActive, onShow }) {
      return (
        <section>
          <h3>{title}</h3>
          {isActive ? <p>{children}</p> : <button onClick={onShow}>Show</button>}
        </section>
      );
    }
    
    function Accordion() {
      const [activeIndex, setActiveIndex] = useState(0);
      return (
        <>
          <Panel title="Hours" isActive={activeIndex === 0} onShow={() => setActiveIndex(0)}>
            Open daily from 8 to 18.
          </Panel>
          <Panel title="Address" isActive={activeIndex === 1} onShow={() => setActiveIndex(1)}>
            Mill Lane 4, near the station.
          </Panel>
        </>
      );
    }
  6. Denksport · Aufgabe 6 von 7

    Knobelaufgabe. Beide Props onShow wurden aus derselben Zeile kopiert. Sie klicken auf Show in Address, dann auf Show in Hours. Welche Panels sind offen?

    function Panel({ title, children, isActive, onShow }) {
      return (
        <section>
          <h3>{title}</h3>
          {isActive ? <p>{children}</p> : <button onClick={onShow}>Show</button>}
        </section>
      );
    }
    
    function Accordion() {
      const [activeIndex, setActiveIndex] = useState(0);
      return (
        <>
          <Panel title="Hours" isActive={activeIndex === 0} onShow={() => setActiveIndex(1)}>
            Open daily from 8 to 18.
          </Panel>
          <Panel title="Address" isActive={activeIndex === 1} onShow={() => setActiveIndex(1)}>
            Mill Lane 4, near the station.
          </Panel>
        </>
      );
    }
  7. Anwenden · Aufgabe 7 von 7

    Kleine Aufgabe: Tabs, die einen State teilen. Schreiben Sie in main.jsx eine Komponente TabButton, die die Props label, isSelected und onSelect nimmt und einen <button> mit aria-pressed={isSelected} rendert. Schreiben Sie eine Komponente Tabs, die zwei TabButtons rendert, Menu und Hours, und ein <p> mit dem Text des gewählten Tabs. Tabs besitzt den State: welcher Tab gewählt ist. Ein Klick auf einen TabButton muss ihn über seine Prop onSelect auswählen.

    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

Ein Akkordeon, das immer ein Panel zeigt

Accordion besitzt activeIndex und gibt jedem Panel zwei Props: isActive, berechnet aus activeIndex, und onShow, eine Funktion, die ihn setzt. Panel hat keinen eigenen State; es wird von seinem Elternteil kontrolliert. Ein Lauf hängt die Komponente nur ein, also klicken Timer unten in main.jsx auf den einzigen Show-Button und geben dann aus, welche Panels offen sind. Im Browser bleibt die Seite aktiv: Klicken Sie selbst auf Show.

main.jsx

import { useState } from 'react';

export default function Accordion() {
  const [activeIndex, setActiveIndex] = useState(0);
  return (
    <>
      <h2>Mill Lane Bakery</h2>
      <Panel
        title="Hours"
        isActive={activeIndex === 0}
        onShow={() => setActiveIndex(0)}
      >
        Open daily from 8 to 18.
      </Panel>
      <Panel
        title="Address"
        isActive={activeIndex === 1}
        onShow={() => setActiveIndex(1)}
      >
        Mill Lane 4, near the station.
      </Panel>
    </>
  );
}

function Panel({ title, children, isActive, onShow }) {
  return (
    <section className="panel">
      <h3>{title}</h3>
      {isActive ? (
        <p>{children}</p>
      ) : (
        <button onClick={onShow}>Show</button>
      )}
    </section>
  );
}

// A run only mounts. Act like a user: show the second panel.
setTimeout(() => {
  document.querySelector('button').click();
  setTimeout(() => {
    const open = [...document.querySelectorAll('section')].filter(s => s.querySelector('p'));
    console.log('Open now:', open.map(s => s.querySelector('h3').textContent).join(', '));
  }, 50);
}, 50);

Ausführen mit

npm run dev

Ausgabe

Open now: Address
<!-- #root -->
<div id="root"><h2>Mill Lane Bakery</h2><section class="panel"><h3>Hours</h3><button>Show</button></section><section class="panel"><h3>Address</h3><p>Mill Lane 4, near the station.</p></section></div>
  • Zu Beginn ist activeIndex 0, also zeigt Hours seinen Text und Address den einzigen Show-Button.
  • Der Klick führte onShow von Address aus, das Accordion geschrieben hat: setActiveIndex(1). Accordion renderte neu, und beide Panels bekamen neue Props isActive.
  • Hours schloss sich ohne Code in Hours: Sein isActive ist jetzt activeIndex === 0, also false.
  • Mit einem dritten Panel gäbe Accordion isActive={activeIndex === 2} und onShow={() => setActiveIndex(2)} weiter; Panel bliebe gleich.
Ä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

Zwei Felder synchron halten

GreetingCard hat zwei Komponenten NameField, eine für die Karte und eine für den Umschlag. Jede hält ihren eigenen State name, also bleibt das andere Feld leer, wenn Sie in eines tippen. Halten Sie beide synchron: Tippen in einem der Felder muss in beiden denselben Text zeigen. Heben Sie den State in GreetingCard an und geben Sie jedem NameField value und onChange weiter; NameField hat danach keinen eigenen State.

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

    Verschieben Sie const [name, setName] = useState(''); und handleChange aus NameField nach GreetingCard.

  2. Hinweis 2

    Rendern Sie <NameField label="…" value={name} onChange={handleChange} /> zweimal.

  3. Hinweis 3

    NameField nimmt { label, value, onChange } und rendert <input value={value} onChange={onChange} />.

Eine Lösung zeigen

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

import { useState } from 'react';

export default function GreetingCard() {
  const [name, setName] = useState('');

  function handleChange(e) {
    setName(e.target.value);
  }

  return (
    <>
      <NameField label="Name on the card" value={name} onChange={handleChange} />
      <NameField label="Name on the envelope" value={name} onChange={handleChange} />
    </>
  );
}

function NameField({ label, value, onChange }) {
  return (
    <label>
      {label}{' '}
      <input value={value} onChange={onChange} />
    </label>
  );
}
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

import { useState } from 'react';

export default function GreetingCard() {
  return (
    <>
      <NameField label="Name on the card" />
      <NameField label="Name on the envelope" />
    </>
  );
}

function NameField({ label }) {
  const [name, setName] = useState('');

  function handleChange(e) {
    setName(e.target.value);
  }

  return (
    <label>
      {label}{' '}
      <input value={name} onChange={handleChange} />
    </label>
  );
}

main.test.jsx

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

const card = () => screen.getByLabelText('Name on the card');
const envelope = () => screen.getByLabelText('Name on the envelope');

test('Beide Felder sind zu Beginn leer', () => {
  render(<GreetingCard />);
  assert.equal(card().value, '', 'zu Beginn enthält das Feld der Karte ' + JSON.stringify(card().value));
  assert.equal(envelope().value, '', 'zu Beginn enthält das Feld des Umschlags ' + JSON.stringify(envelope().value));
});

test('Tippen auf der Karte füllt den Umschlag', () => {
  render(<GreetingCard />);
  fireEvent.change(card(), {target: {value: 'Ada'}});
  assert.equal(card().value, 'Ada', 'das Feld der Karte enthält ' + JSON.stringify(card().value));
  assert.equal(envelope().value, 'Ada', 'nach Ada auf der Karte enthält das Feld des Umschlags ' + JSON.stringify(envelope().value));
});

test('Tippen auf dem Umschlag füllt die Karte', () => {
  render(<GreetingCard />);
  fireEvent.change(card(), {target: {value: 'Ada'}});
  fireEvent.change(envelope(), {target: {value: 'Grace'}});
  assert.equal(card().value, 'Grace', 'nach Grace auf dem Umschlag enthält das Feld der Karte ' + JSON.stringify(card().value));
  assert.equal(envelope().value, 'Grace', 'das Feld des Umschlags enthält ' + JSON.stringify(envelope().value));
});

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

Ein Suchfeld, das eine Liste filtert

FilterableList rendert eine SearchBar und eine List mit Früchten. SearchBar hält die Suche in ihrem eigenen State, also erfährt List nie davon und zeigt immer alle sechs Früchte. Heben Sie query in FilterableList an, geben Sie es mit einem Handler onChange an SearchBar weiter und geben Sie List nur die Früchte, deren Name die Suche enthält, ohne Rücksicht auf Groß- und Kleinschreibung. Eine leere Suche zeigt alle Früchte.

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

    FilterableList ist der nächste gemeinsame Elternteil von SearchBar und List, also gehört der State query dorthin.

  2. Hinweis 2

    SearchBar nimmt { query, onChange } und rendert <input value={query} onChange={onChange} />.

  3. Hinweis 3

    const visible = fruits.filter(item => item.toLowerCase().includes(query.toLowerCase())); und dann items={visible} weitergeben.

Eine Lösung zeigen

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

import { useState } from 'react';

const fruits = ['Strawberry', 'Blueberry', 'Banana', 'Gooseberry', 'Cherry', 'Raspberry'];

export default function FilterableList() {
  const [query, setQuery] = useState('');
  const visible = fruits.filter(item =>
    item.toLowerCase().includes(query.toLowerCase())
  );

  return (
    <>
      <SearchBar query={query} onChange={e => setQuery(e.target.value)} />
      <hr />
      <List items={visible} />
    </>
  );
}

function SearchBar({ query, onChange }) {
  return (
    <label>
      Search:{' '}
      <input value={query} onChange={onChange} />
    </label>
  );
}

function List({ items }) {
  return (
    <ul>
      {items.map(item => (
        <li key={item}>{item}</li>
      ))}
    </ul>
  );
}
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

import { useState } from 'react';

const fruits = ['Strawberry', 'Blueberry', 'Banana', 'Gooseberry', 'Cherry', 'Raspberry'];

export default function FilterableList() {
  return (
    <>
      <SearchBar />
      <hr />
      <List items={fruits} />
    </>
  );
}

function SearchBar() {
  const [query, setQuery] = useState('');
  return (
    <label>
      Search:{' '}
      <input value={query} onChange={e => setQuery(e.target.value)} />
    </label>
  );
}

function List({ items }) {
  return (
    <ul>
      {items.map(item => (
        <li key={item}>{item}</li>
      ))}
    </ul>
  );
}

main.test.jsx

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

const search = () => screen.getByLabelText('Search:');
const shown = () => screen.queryAllByRole('listitem').map((li) => li.textContent).join(', ');

test('Zu Beginn erscheinen alle sechs Früchte', () => {
  render(<FilterableList />);
  assert.equal(shown(), 'Strawberry, Blueberry, Banana, Gooseberry, Cherry, Raspberry', 'zu Beginn zeigt die Liste ' + JSON.stringify(shown()));
});

test('Mit berry bleiben nur die Beeren', () => {
  render(<FilterableList />);
  fireEvent.change(search(), {target: {value: 'berry'}});
  assert.equal(search().value, 'berry', 'das Suchfeld enthält ' + JSON.stringify(search().value));
  assert.equal(shown(), 'Strawberry, Blueberry, Gooseberry, Raspberry', 'nach berry zeigt die Liste ' + JSON.stringify(shown()));
});

test('Die Suche ignoriert Groß- und Kleinschreibung', () => {
  render(<FilterableList />);
  fireEvent.change(search(), {target: {value: 'CHERRY'}});
  assert.equal(shown(), 'Cherry', 'nach CHERRY zeigt die Liste ' + JSON.stringify(shown()));
});

test('Eine geleerte Suche zeigt wieder alle Früchte', () => {
  render(<FilterableList />);
  fireEvent.change(search(), {target: {value: 'ban'}});
  assert.equal(shown(), 'Banana', 'nach ban zeigt die Liste ' + JSON.stringify(shown()));
  fireEvent.change(search(), {target: {value: ''}});
  assert.equal(shown(), 'Strawberry, Blueberry, Banana, Gooseberry, Cherry, Raspberry', 'nach dem Leeren der Suche zeigt die Liste ' + JSON.stringify(shown()));
});

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

Eine Handler-Prop aufrufen, die der Elternteil nie übergeben hat

import { useState } from 'react';

export default function Accordion() {
  const [activeIndex, setActiveIndex] = useState(0);
  return (
    <>
      <Panel title="Hours" isActive={activeIndex === 0}>
        Open daily from 8 to 18.
      </Panel>
      <Panel title="Address" isActive={activeIndex === 1}>
        Mill Lane 4, near the station.
      </Panel>
    </>
  );
}

function Panel({ title, children, isActive, onShow }) {
  return (
    <section>
      <h3>{title}</h3>
      {isActive ? <p>{children}</p> : <button onClick={() => onShow()}>Show</button>}
    </section>
  );
}

// A run only mounts. Act like a user: click Show.
setTimeout(() => document.querySelector('button').click(), 50);

Was React ausgibt

TypeError: onShow is not a function

Warum, und die Lösung

Accordion gibt isActive weiter, aber kein onShow, also ist die Prop undefined, und ihr Aufruf wirft beim Klick auf den Button (Wortlaut von Chrome und Node; Firefox und Safari formulieren ihn anders). Geben Sie den Handler aus dem Elternteil mit: onShow={() => setActiveIndex(1)}. State anheben heißt immer, beides weiterzugeben: den Wert und einen Weg, ihn zu ändern.

Ein Handler, der ein Event erwartet, aber einen Wert bekommt

import { useState } from 'react';

export default function FilterableList() {
  const [query, setQuery] = useState('');
  return (
    <>
      <SearchBar query={query} onQueryChange={e => setQuery(e.target.value)} />
      <p>Searching for: {query}</p>
    </>
  );
}

function SearchBar({ query, onQueryChange }) {
  return <input value={query} onChange={e => onQueryChange(e.target.value)} />;
}

// A run only mounts. Act like a user: type b into the field.
setTimeout(() => {
  const input = document.querySelector('input');
  Object.getOwnPropertyDescriptor(Object.getPrototypeOf(input), 'value').set.call(input, 'b');
  input.dispatchEvent(new window.Event('input', { bubbles: true }));
}, 50);

Was React ausgibt

TypeError: Cannot read properties of undefined (reading 'value')

Warum, und die Lösung

SearchBar ruft schon onQueryChange(e.target.value) auf, also bekommt der Handler des Elternteils den String 'b', und 'b'.target ist undefined (Wortlaut von Chrome und Node; Firefox und Safari formulieren ihn anders). Einigen Sie sich auf eine Form: Entweder gibt das Kind den Wert weiter, und der Elternteil schreibt onQueryChange={setQuery}, oder das Kind reicht das Event mit onChange={onQueryChange} durch.

Angehobener State, der mit undefined beginnt

import { useState } from 'react';

export default function FilterableList() {
  const [query, setQuery] = useState();
  return (
    <>
      <SearchBar query={query} onQueryChange={setQuery} />
      <p>Searching for: {query}</p>
    </>
  );
}

function SearchBar({ query, onQueryChange }) {
  return <input value={query} onChange={e => onQueryChange(e.target.value)} />;
}

// A run only mounts. Act like a user: type b into the field.
setTimeout(() => {
  const input = document.querySelector('input');
  Object.getOwnPropertyDescriptor(Object.getPrototypeOf(input), 'value').set.call(input, 'b');
  input.dispatchEvent(new window.Event('input', { bubbles: true }));
}, 50);

Was React ausgibt

A component is changing an uncontrolled input to be controlled.

Warum, und die Lösung

useState() ohne Argument beginnt query mit undefined, also gibt das erste Rendern value={undefined} weiter, was React als unkontrolliertes Eingabefeld behandelt. Der erste Tastendruck setzt einen String, und React warnt. Beginnen Sie den angehobenen State mit einem Wert des richtigen Typs: useState('').

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

Geteilten State in den nächsten gemeinsamen Elternteil anheben

Zwei Panels, die jeweils einen eigenen State isActive halten, sind unabhängig: Öffnen Sie eines, bleibt das andere, wie es ist. Damit sie sich gemeinsam ändern, heben Sie ihren State in drei Schritten an. Entfernen Sie den State aus den Kindern und lesen Sie isActive stattdessen aus den Props. Geben Sie aus dem nächsten gemeinsamen Elternteil feste Werte mit, um zu sehen, dass die Props wirken. Fügen Sie dann diesem Elternteil State hinzu. Anheben ändert oft, was Sie speichern: Nur ein Panel darf offen sein, also hält der Elternteil eine Zahl, activeIndex, statt zweier Booleans und gibt dem ersten Panel isActive={activeIndex === 0}.

Einen Handler weitergeben: Das Kind bittet, der Elternteil ändert

State gehört privat der Komponente, die ihn deklariert, also kann ein Panel setActiveIndex nicht aufrufen: Diese Funktion lebt in Accordion. Der Elternteil gibt zusätzlich einen Handler als Prop weiter, onShow={() => setActiveIndex(1)}, und das Panel ruft ihn über seinen Button auf: <button onClick={onShow}>. Der Klick führt die Funktion des Elternteils aus, dessen State ändert sich, und React rendert den Elternteil neu, mit neuen Props für jedes Kind. Ein Kind kann auch einen Wert nach oben geben, etwa onSearch(e.target.value); dann muss der Handler des Elternteils einen Wert erwarten, kein Event.

Kontrolliert, unkontrolliert und ein Besitzer pro State

react.dev nennt eine Komponente unkontrolliert, wenn sie die wichtige Information in ihrem eigenen lokalen State hält, wie das erste Panel, das sein Elternteil weder öffnen noch schließen kann. Kontrolliert ist sie, wenn diese Information aus Props kommt; dann legt der Elternteil ihr Verhalten vollständig fest. Unkontrollierte Komponenten sind leichter einzusetzen; kontrollierte sind flexibler, brauchen aber mehr Props. Streng sind die Begriffe nicht: Die meisten Komponenten mischen beides. Wählen Sie für jedes Stück State eine Komponente, die es besitzt, eine einzige Quelle der Wahrheit. Kopieren Sie geteilten State nicht in zwei Komponenten; heben Sie ihn an und geben Sie ihn weiter.

Quellen

Zuletzt geprüft am 5. Oktober 2026