Zum Inhalt springen

7.2 React-Grundlagen: JSX und Komponenten

Zu Zen-Modus wechseln

Nach dieser Einheit kannst du:

  • die JavaScript-Sprachmittel nennen, die React ständig verwendet, und ternären Operator, && und Funktionen als Werte sicher lesen.
  • JSX nach seinen Spielregeln schreiben: Ausdrücke in geschweiften Klammern, className, geschlossene Tags, ein Wurzelelement oder Fragment.
  • Funktionskomponenten in eigenen Dateien anlegen, benannt exportieren und in anderen Komponenten verwenden.
  • entscheiden, ob ein Stück Code eine Komponente oder eine gewöhnliche Funktion sein soll.

Eine Seite aus Legosteinen: Ein Stein mit vier Noppen wird einmal entworfen und dann hundertfach verbaut, mal rot, mal blau, mal als Dach, mal als Wand. Niemand gießt für jede Stelle einen eigenen Stein. Genau so entsteht eine React-Oberfläche: Ein Baustein, die Komponente, wird einmal geschrieben und danach mit unterschiedlichen Daten immer wieder verwendet.

flowchart TD
    accTitle: Eine Seite aus wiederverwendbaren Komponenten
    app["App"] --> header["Header"]
    app --> list["JobList"]
    list --> c1["JobCard<br/>intro.mp4"]
    list --> c2["JobCard<br/>outro.mp4"]
    list --> c3["JobCard<br/>trailer.mp4"]

Abb. 7.6: Eine Komponente, dreimal verwendet, jedes Mal mit anderen Daten (eigene Darstellung).

Die Schreibweise, in der Komponenten ihre Oberfläche beschreiben, heißt JSX. Sie sieht aus wie HTML, ist aber TypeScript, und sie verwendet konsequent die modernen Sprachmittel aus Kapitel 1. Deshalb beginnt diese Einheit mit einer kurzen Prüfliste der JavaScript-Grundlagen, dann folgen JSX und Komponenten. Durchgehendes Beispiel des Kapitels ist wieder die Render-Farm aus Kapitel 6: Aufträge (jobs) mit Dateiname, Zustand und Fortschritt.

  • JSX: HTML-artige Syntax mitten im TypeScript; Dateien mit JSX enden auf .tsx.
  • Ausdruck: ein Stück Code, das einen Wert ergibt (count + 1, a ? b : c); eine Anweisung wie if ergibt keinen.
  • Fragment: <>...</>, eine unsichtbare Klammer um mehrere Elemente, die kein HTML-Element erzeugt.
  • Funktionskomponente: eine Funktion, deren Name groß beginnt und die JSX zurückgibt.
  • Benannter Export: export function JobCard, beim Import steht der Name in geschweiften Klammern fest.

React erfindet keine neue Sprache. Wer die Sprachmittel aus Kapitel 1 sicher beherrscht, liest React-Code flüssig; wer nicht, hält gewöhnliches JavaScript für React-Magie. Die Übersicht ist deine Prüfliste; die Beispiele danach sind bewusst reines JavaScript, weil es hier um Sprachmittel geht und noch nicht um Komponenten.

SprachmittelWo es in React ständig vorkommtEinheit in Kapitel 1
Arrow FunctionsEvent-Handler, Callbacks in map, Setter-Funktionen1.2, Funktionen und Arrow Functions
DestructuringProps entpacken, const [value, setValue] = useState(...)1.4, Destructuring
Spread und RestState unverändert kopieren und ergänzen1.4, Spread und Rest
map, filter, reduceListen rendern, Werte aus Daten ableiten1.2, Arrays und ihre Methoden
Module (import/export)jede Komponente in einer eigenen Datei1.4, Module
Optional Chaining ?. und ??Daten, die es noch nicht gibt1.4, Optional Chaining

Drei Kleinigkeiten daraus tauchen in JSX so häufig auf, dass sie hier noch einmal ausdrücklich stehen.

Der ternäre Operator ist die Ausdrucksform der Verzweigung. Deshalb kommt er in React so oft vor: In JSX sind nur Ausdrücke erlaubt, ein if ist keiner.

const age = 20;
const status = age >= 18 ? "volljährig" : "minderjährig";

Der &&-Operator ist die Kurzform für “nur wenn”: Er wertet die rechte Seite nur aus, wenn die linke wahr ist.

const isFailed = true;
isFailed && console.log("needs attention"); // short for: if (isFailed) { ... }

Funktionen als Werte sind die Grundlage jedes Event-Handlers: Eine Funktion kann in einer Variablen stehen und als Argument übergeben werden, ohne aufgerufen zu werden.

const double = (n) => n * 2;
const apply = (fn, value) => fn(value); // fn is a parameter, not a call
apply(double, 21); // 42

Beispielprojekt: 07_react_grundlagen_examples/ex04_js_for_react

Der Unterschied zwischen double (die Funktion) und double(21) (ihr Ergebnis) wird in Einheit 7.3 bei den Events zum häufigsten Anfängerfehler überhaupt.

flowchart LR
    accTitle: Funktion übergeben oder Ergebnis übergeben
    fn["double<br/>die Funktion"] -- "übergeben" --> later["wird später<br/>aufgerufen"]
    fnCall["double(21)<br/>ein Aufruf"] -- "läuft sofort" --> value["übergeben wird<br/>der Wert 42"]

Abb. 7.7: Ohne Klammern wandert die Funktion weiter, mit Klammern nur ihr Ergebnis (eigene Darstellung).

Eine Komponente ist eine Funktion, die Oberfläche zurückgibt. Die Schreibweise dafür ist JSX: HTML-artige Syntax mitten im TypeScript, in die du mit geschweiften Klammern beliebige Ausdrücke einbettest.

function Greeting() {
const character = "Iron Man";
return <h1>Hello {character.toUpperCase()}</h1>;
}

Alles zwischen { und } ist gewöhnliches TypeScript: Variablen, Rechnungen, Funktionsaufrufe, ternäre Operatoren. Das Ergebnis wird an dieser Stelle gerendert, im Beispiel <h1>Hello IRON MAN</h1>.

Die JSX-Spielregeln:

  • Komponentennamen beginnen groß (JobCard); kleingeschriebene Tags hält React für HTML-Elemente.
  • {...} bettet Ausdrücke ein. Anweisungen (if, for) gehören nicht hinein, wohl aber deren Ausdrucksformen (ternärer Operator, &&, map).
  • Statt class heißt das Attribut className (class ist in JavaScript reserviert); statt for bei Labels heißt es htmlFor.
  • Jedes Element wird geschlossen, auch die in HTML nachlässig behandelten: <br />, <img ... />.
  • Eine Komponente gibt ein Wurzelelement zurück; mehrere Geschwister umschließt ein Fragment <>...</>.

Der letzte Punkt ist der häufigste Anfängerfehler. Das hier ist ungültig, weil zwei <div> nebeneinander zurückgegeben werden:

// does not compile: two root elements
return (
<div>...</div>
<div>...</div>
);

Ein zusätzliches <div> drumherum würde zwar helfen, verändert aber die HTML-Struktur und damit womöglich das CSS. Das Fragment löst das Problem, ohne ein Element zu erzeugen:

return (
<>
<div>...</div>
<div>...</div>
</>
);

JSX-Ausdrücke sind gewöhnliche Werte: Sie lassen sich in Variablen ablegen, aus Funktionen zurückgeben und in Arrays sammeln.

function Profile() {
const username = "Bart";
const heading = <h2>{username}</h2>; // a value like any other
return <div>{heading}</div>;
}

Genauer erklärt: Was hier wie HTML aussieht, ist keines. Vite übersetzt jedes JSX-Element in einen Funktionsaufruf, der ein einfaches Objekt erzeugt, ungefähr { type: "h2", props: { children: "Bart" } }. Genau diese Objekte bilden den Virtual DOM aus Einheit 7.1. Daraus folgt auch, warum nur ein Wurzelelement erlaubt ist: Eine Funktion kann genau einen Wert zurückgeben, und zwei Geschwisterelemente wären zwei.

flowchart LR
    accTitle: Aus JSX wird ein Objekt
    jsx["JSX<br/>&lt;h2&gt;Bart&lt;/h2&gt;"] --> fnCall["Funktionsaufruf<br/>beim Übersetzen"]
    fnCall --> obj["Objekt<br/>type: h2<br/>children: Bart"]
    obj --> vdom["Teil des<br/>Virtual DOM"]

Abb. 7.8: JSX ist eine Kurzschrift für Objekte, aus denen der Virtual DOM besteht (eigene Darstellung).

Ein Sonderfall der geschweiften Klammern sind Objekte in JSX. Weil Objektliterale selbst geschweifte Klammern haben, entsteht ein doppeltes Paar, das äußere für “hier kommt TypeScript”, das innere für das Objekt:

<li style={{ color: "darkgreen", fontWeight: "bold" }}>Gandalf</li>

Beispielprojekt: 07_react_grundlagen_examples/ex05_jsx_rules

Inline-Styles sind der Regelfall für diese Schreibweise, aber nicht der Regelfall für Gestaltung: Für alles Wiederkehrende bleiben CSS-Klassen über className die bessere Wahl.

Zur Schreibweise: Im Kurs formatiert Biome den Code (Einheit 1.1), und seine Voreinstellung setzt doppelte Anführungszeichen, für JSX-Attribute wie für gewöhnliche Strings. Deshalb stehen in allen Beispielen doppelte Anführungszeichen. Wer bestehendes HTML übernehmen will, spart sich die Handarbeit mit dem Konverter transform.tools/html-to-jsx: Er ersetzt class durch className und schließt offene Tags.

Auflösung
  1. class muss className heißen.
  2. <br> muss geschlossen werden: <br />.
  3. Drei Geschwister ohne gemeinsames Wurzelelement: Ein Fragment <>...</> gehört drumherum.
  4. jobCounter beginnt klein und wird deshalb als HTML-Element behandelt; als Komponente muss es JobCounter heißen.

Eine React-Anwendung besteht aus Komponenten. Historisch gab es sie in zwei Bauformen, als Klasse und als Funktion; heute sind Funktionskomponenten der Standard, und nur sie kommen in diesem Kurs vor. Klassenkomponenten begegnen dir höchstens in altem Code.

src/components/JobCard.tsx
interface JobCardProps {
filename: string;
progress: number; // 0 to 1
}
export function JobCard({ filename, progress }: JobCardProps) {
return (
<section className="job-card">
<h3>{filename}</h3>
<p>{Math.round(progress * 100)} % rendered</p>
</section>
);
}

Verwendet wird sie wie ein eigenes HTML-Element, in der Datei, die sie importiert:

src/App.tsx
import { JobCard } from "./components/JobCard";
export default function App() {
return (
<main>
<JobCard filename="intro.mp4" progress={0.62} />
<JobCard filename="outro.mp4" progress={0.1} />
</main>
);
}

Beispielprojekt: 07_react_grundlagen_examples/ex07_job_card

Die Attribute filename und progress sind die Props der Komponente, ihre Eingabedaten; das interface darüber beschreibt, welche sie erwartet. Props bekommen in Einheit 7.3 einen eigenen Abschnitt. Die Regeln für Komponenten:

  1. Eine Komponente ist eine Funktion, die JSX zurückgibt.
  2. Ihr Name beginnt mit einem Großbuchstaben. React unterscheidet daran Komponenten von HTML-Elementen.
  3. Sie wohnt in einer eigenen Datei unter src/components/, benannt wie die Komponente (JobCard.tsx).
  4. Sie wird exportiert, damit andere Dateien sie importieren können.
  5. Sie bekommt ihre Daten ausschließlich über Props und liest niemals aus dem DOM.
flowchart LR
    accTitle: Datei, Export und Verwendung einer Komponente
    file["components/JobCard.tsx<br/>export function JobCard"] -- "import { JobCard }" --> app["App.tsx"]
    app -- "&lt;JobCard filename=... /&gt;" --> c1["Karte 1"]
    app -- "&lt;JobCard filename=... /&gt;" --> c2["Karte 2"]

Abb. 7.9: Eine Datei pro Komponente, ein Import, beliebig viele Verwendungen (eigene Darstellung).

Für den Export gibt es zwei Formen: export function JobCard() {...} (benannt) und export default function JobCard() {...} (Standardexport). Im Kurs gilt: benannter Export für alle Komponenten, weil der Name dann beim Import feststeht und Tippfehler auffallen; der Standardexport bleibt der Wurzelkomponente App vorbehalten, weil Vite sie so erzeugt. Beide Formen sind verbreitet, und du wirst beiden begegnen.

Wo begegnet dir das? In jeder größeren Website: Die Produktkacheln eines Online-Shops, die Beitragskarten eines sozialen Netzwerks oder die Videovorschauen einer Streamingseite sind jeweils ein und derselbe Baustein, hundertfach mit anderen Daten gerendert.

Nicht jede Funktion in einer React-Datei ist eine Komponente. Die Abgrenzung:

SituationWas es sein soll
wiederverwendbarer Oberflächenbaustein mit PropsKomponente
braucht eigenen Zustand oder HooksKomponente
berechnet nur einen Wert (Datum formatieren, Summe bilden)gewöhnliche Funktion
erzeugt ein kleines Stück JSX innerhalb einer Komponentegewöhnliche Funktion oder Variable

Faustregel: Eine Komponente ist, was in JSX als <Name /> auftaucht. Alles andere ist eine gewöhnliche Funktion, und die gehört, wenn sie nichts mit der Anzeige zu tun hat, in eine eigene Datei außerhalb von components/.

Auflösung

(a) und (c) sind gewöhnliche Funktionen: Sie berechnen nur einen Wert und geben kein JSX zurück. (b) und (d) sind Komponenten (ProgressBar, CancelButton): wiederverwendbare Oberflächenbausteine, die in JSX als <Name /> auftauchen.

  1. Zwei Wurzelelemente: return (<div /> <div />) kompiliert nicht; ein Fragment <>...</> gehört drumherum.
  2. class statt className, <br> ohne Schrägstrich: die JSX-Klassiker der ersten Woche.
  3. Komponente kleingeschrieben: <jobCard /> hält React für ein HTML-Element; TypeScript meldet beim Build, dass es dieses Element nicht gibt.
  4. if in geschweiften Klammern: In JSX sind nur Ausdrücke erlaubt; der ternäre Operator ist die Ausdrucksform.
  5. Komponente nicht exportiert: Der Import in App.tsx schlägt fehl.

Du kannst dir diese Einheit kostenlos mit der Vorlesefunktion deines Browsers oder Betriebssystems vorlesen lassen (etwa „Laut vorlesen” in Edge), ohne Konto und ohne Upload; die JSX-Beispiele liest du dabei am Bildschirm mit. Freiwillig kannst du mit Google NotebookLM (Google-Konto nötig) aus diesem öffentlichen Text eine gesprochene Zusammenfassung erzeugen, auch auf Deutsch.

Du kannst jetzt:

  • die JavaScript-Sprachmittel nennen, die React ständig verwendet, und ternären Operator, && und Funktionen als Werte sicher lesen.
  • JSX nach seinen Spielregeln schreiben: Ausdrücke in geschweiften Klammern, className, geschlossene Tags, ein Wurzelelement oder Fragment.
  • Funktionskomponenten in eigenen Dateien anlegen, benannt exportieren und in anderen Komponenten verwenden.
  • entscheiden, ob ein Stück Code eine Komponente oder eine gewöhnliche Funktion sein soll.
  • Aufgabe 07-1a - Komponenten-Baukasten, Stufe Wesentlich_überwiegend
  • JSX-Regeln, className, Fragment → react.dev: Writing markup with JSX, JavaScript in JSX with curly braces
  • Funktionskomponenten, Export → react.dev: Your first component, Importing and exporting components
  • JSX als Objekte → react.dev: createElement
  • Doppelte Anführungszeichen als Voreinstellung von Biome → eigener Test mit Biome 2.5.15 (Oktober 2026)
  • Compiler-Meldungen zu zwei Wurzelelementen und zu <jobCard /> → eigener Test mit TypeScript 6.0.3 aus der Vite-Vorlage (Oktober 2026), siehe README der Beispielprojekte
  • Abb. 7.6 (Komponentenbaum), Abb. 7.7 (Funktion oder Ergebnis), Abb. 7.8 (JSX als Objekt), Abb. 7.9 (Datei, Export, Verwendung) → eigene Darstellung, alle als Mermaid-Diagramm
  • Oliver Maurhart (MAO)
  • Michael Gabriel (GAM)

CC-BY-SA

https://qiz.at/rules