Zum Inhalt springen
aviral gupta

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

JSX und geschweifte Klammern

Nach dieser Lektion wandeln Sie HTML in gültiges JSX um, setzen mit geschweiften Klammern JavaScript ein und gestalten Elemente mit einem Style-Objekt.

Lektion 2 von 6 in B2 Die Oberfläche beschreiben

Danach können Sie

  • JSX nach seinen Regeln schreiben: eine Wurzel oder ein Fragment, geschlossene Tags, camelCase-Attribute, aria-* und data-* mit Bindestrich
  • Strings in Anführungszeichen und JavaScript in geschweiften Klammern übergeben, als Text im Tag oder direkt nach =
  • Objekte mit doppelten Klammern übergeben, etwa style={{ backgroundColor: 'black' }}, und Werte aus einem Objekt lesen
  1. Aufwärmen · Aufgabe 1 von 7

    Zum Aufwärmen aus Lektion B2.1: eine Komponente, einmal definiert und mehrfach verwendet. Wie viele <li>-Elemente rendert TodoList?

    function Task() {
      return <li>Buy milk</li>;
    }
    
    function TodoList() {
      return (
        <ul>
          <Task />
          <Task />
          <Task />
        </ul>
      );
    }
  2. Vorhersagen · Aufgabe 2 von 7

    Sagen Sie voraus, bevor Sie weiterlesen. Die Klammern stehen innerhalb der Anführungszeichen. Welches src hat das Bild?

    const avatar = 'hedy.jpg';
    
    function Avatar() {
      return <img src="{avatar}" alt="Hedy Lamarr" />;
    }
  3. Üben · Aufgabe 3 von 7

    Ergänzen Sie die Style-Eigenschaft, die der Überschrift einen schwarzen Hintergrund gibt, wie background-color in CSS.

    <h1 style={{ ____: 'black' }}>Todos</h1>
    <h1 style={{ : 'black' }}>Todos</h1>
  4. Üben · Aufgabe 4 von 7

    Ordnen Sie jedem HTML-Attribut zu, wie Sie es in JSX schreiben.

  5. Üben · Aufgabe 5 von 7

    Was steht auf der Seite im style-Attribut des <div>?

    const person = {
      name: 'Hedy Lamarr',
      theme: { backgroundColor: 'black', color: 'pink' }
    };
    
    function TodoHeader() {
      return (
        <div style={person.theme}>
          <h1>{person.name}'s Todos</h1>
        </div>
      );
    }
  6. Denksport · Aufgabe 6 von 7

    Knobelaufgabe. Manche Template-Sprachen setzen Variablen in doppelte Klammern (Ergebnis auf Englisch: nothing = nichts, an error = ein Fehler). Was zeigt diese Überschrift in React?

    const name = 'Hedy';
    
    function Title() {
      return <h1>{{name}}</h1>;
    }
  7. Anwenden · Aufgabe 7 von 7

    Mini-Aufgabe: Ihre eigene To-do-Liste. Legen Sie in main.jsx ein Objekt person mit einem Namen und einem theme (backgroundColor und color) an und ein Array tasks mit drei Strings. Der Default-Export rendert eine <section>, gestaltet mit person.theme und mit einem aria-label, eine Überschrift "<Name>'s Todos (<Anzahl>)", die drei Aufgaben in einer Liste, ein geschlossenes <hr /> und eine kleine Notiz mit style={{ fontSize: 12 }}. Lesen Sie jeden Wert mit geschweiften Klammern. Führen Sie es aus und prüfen Sie, dass React keine Warnung ausgibt.

    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

Der Kopf einer To-do-Liste

Der Kopf einer To-do-Liste, im Stil der Beispiele auf react.dev. Das Objekt person enthält einen Namen, ein Bild und ein theme; der Header liest alles mit geschweiften Klammern, und style={person.theme} gibt das theme-Objekt weiter. Das SVG-Häkchen verwendet strokeWidth, den camelCase-Namen, während data-day und aria-label ihre Bindestriche behalten. Die Notiz bekommt ein Inline-Style-Objekt in doppelten Klammern. Der Snapshot zeigt, was React aus jedem Attribut gemacht hat.

main.jsx

const person = {
  name: 'Hedy Lamarr',
  imageUrl: 'hedy-lamarr.jpg',
  theme: {
    backgroundColor: 'black',
    color: 'pink'
  }
};

const today = 'Monday';

export default function TodoHeader() {
  return (
    <header style={person.theme} data-day={today}>
      <img className="avatar" src={person.imageUrl} alt={person.name} />
      <h1>{person.name}'s Todos for {today}</h1>
      <svg width="24" height="24" aria-label="Done">
        <path d="M4 12l5 5L20 6" stroke="pink" strokeWidth={2} fill="none" />
      </svg>
      <p style={{ fontStyle: 'italic' }}>3 tasks left</p>
    </header>
  );
}

Ausführen mit

npm run dev

Ausgabe

<!-- #root -->
<div id="root"><header style="background-color: black; color: pink;" data-day="Monday"><img class="avatar" alt="Hedy Lamarr" src="hedy-lamarr.jpg"><h1>Hedy Lamarr's Todos for Monday</h1><svg width="24" height="24" aria-label="Done"><path d="M4 12l5 5L20 6" stroke="pink" stroke-width="2" fill="none"></path></svg><p style="font-style: italic;">3 tasks left</p></header></div>
  • Aus className wurde class, aus strokeWidth stroke-width, und die Style-Objekte wurden zu CSS-Text mit Bindestrichen.
  • data-day und aria-label stehen wie in HTML mit Bindestrich da und bleiben so.
  • strokeWidth={2} übergibt eine Zahl; die Seite zeigt sie als Text "2".
  • Die schließenden Schrägstriche von <img /> und <path /> gibt es nur in JSX: Im HTML stehen <img> und ein Paar <path></path>.
Ä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 eingefügtes Formular in JSX umwandeln

Jemand hat das Formular einer To-do-App aus einer HTML-Seite eingefügt. Es wird gerendert, aber React gibt vier Warnungen aus. Schreiben Sie die Attribute auf JSX-Art, sodass React keine mehr ausgibt, und erhalten Sie, was sie bewirken: Das Label gehört weiter zum Feld, das Icon behält seine Strichstärke 2, aria-label bleibt, wie es ist. Geben Sie dann dem Add-Button mit einem Inline-Style-Objekt einen schwarzen Hintergrund.

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 aus und lesen Sie die Warnungen: Jede nennt das Attribut und die Korrektur.

  2. Hinweis 2

    class, for, tabindex und stroke-width werden zu className, htmlFor, tabIndex und strokeWidth; aria-label behält seinen Bindestrich.

  3. Hinweis 3

    Der Style ist ein Objekt in Klammern: style={{ backgroundColor: 'black' }}.

Eine Lösung zeigen

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

export default function TodoForm() {
  return (
    <form className="todo-form">
      <label htmlFor="task">New task</label>
      <input id="task" type="text" tabIndex="1" />
      <button type="submit" aria-label="Add task" style={{ backgroundColor: 'black' }}>
        <svg width="16" height="16">
          <path d="M8 2v12M2 8h12" stroke="white" strokeWidth="2" />
        </svg>
      </button>
    </form>
  );
}
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

// Pasted from an HTML page. Make it warning-free JSX, and give the Add
// button a black background with an inline style object.
export default function TodoForm() {
  return (
    <form class="todo-form">
      <label for="task">New task</label>
      <input id="task" type="text" tabindex="1" />
      <button type="submit" aria-label="Add task">
        <svg width="16" height="16">
          <path d="M8 2v12M2 8h12" stroke="white" stroke-width="2" />
        </svg>
      </button>
    </form>
  );
}

main.test.jsx

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

test('Das Label New task gehört zum Textfeld', () => {
  render(<TodoForm />);
  const input = screen.getByLabelText('New task');
  assert.equal(input.id, 'task', 'das Label zeigt auf das Element mit der id ' + JSON.stringify(input.id));
});

test('Der Add-Button behält sein aria-label', () => {
  render(<TodoForm />);
  assert.ok(screen.queryByRole('button', {name: 'Add task'}), 'kein Button heißt Add task');
});

test('Der Add-Button hat einen schwarzen Hintergrund', () => {
  render(<TodoForm />);
  const background = screen.getByRole('button', {name: 'Add task'}).style.backgroundColor;
  assert.equal(background, 'black', 'der Button hat background-color ' + JSON.stringify(background));
});

test('Das Icon behält die Strichstärke 2', () => {
  const {container} = render(<TodoForm />);
  const width = container.querySelector('path').getAttribute('stroke-width');
  assert.equal(width, '2', 'der Pfad hat stroke-width=' + JSON.stringify(width));
});

test('Das Formular hat die CSS-Klasse todo-form', () => {
  const {container} = render(<TodoForm />);
  const className = container.querySelector('form').className;
  assert.equal(className, 'todo-form', 'das Formular hat die Klasse ' + JSON.stringify(className));
});

test('React gibt keine Warnungen aus', () => {
  const warnings = [];
  const original = console.error;
  console.error = (...args) => warnings.push(args.join(' '));
  try {
    render(<TodoForm />);
  } finally {
    console.error = original;
  }
  assert.deepEqual(warnings, [], 'console.error beim Rendern');
});

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 Avatar, gestaltet aus einem Objekt

TodoHeader zeigt das Objekt person, aber jeder Wert steht in Anführungszeichen. Lesen Sie sie mit geschweiften Klammern: das src des Bildes aus person.imageUrl, sein alt aus person.name und die Überschrift "<name>'s Todos". Machen Sie das Bild mit einem Style-Objekt person.imageSize Pixel breit und hoch, und gestalten Sie den <header> mit person.theme. Das Bild lädt 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 Überschrift zeigt die Wörter person.name, denn sie sind Text, kein JavaScript.

  2. Hinweis 2

    Ersetzen Sie die Anführungszeichen durch Klammern: src={person.imageUrl} und in der Überschrift {person.name}'s Todos.

  3. Hinweis 3

    Größen stehen in doppelten Klammern, style={{ width: person.imageSize, height: person.imageSize }}; eine Zahl bedeutet Pixel. Der Header bekommt style={person.theme}.

Eine Lösung zeigen

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

const person = {
  name: 'Gregorio Y. Zara',
  imageUrl: 'gregorio-zara.jpg',
  imageSize: 90,
  theme: {
    backgroundColor: 'black',
    color: 'pink'
  }
};

export default function TodoHeader() {
  return (
    <header style={person.theme}>
      <img
        className="avatar"
        src={person.imageUrl}
        alt={person.name}
        style={{ width: person.imageSize, height: person.imageSize }}
      />
      <h1>{person.name}'s Todos</h1>
    </header>
  );
}
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

const person = {
  name: 'Gregorio Y. Zara',
  imageUrl: 'gregorio-zara.jpg',
  imageSize: 90,
  theme: {
    backgroundColor: 'black',
    color: 'pink'
  }
};

export default function TodoHeader() {
  // TODO: read every value from person with curly braces, and add the styles.
  return (
    <header>
      <img className="avatar" src="person.imageUrl" alt="person.name" />
      <h1>person.name's Todos</h1>
    </header>
  );
}

main.test.jsx

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

test("Die Überschrift lautet Gregorio Y. Zara's Todos", () => {
  render(<TodoHeader />);
  const heading = screen.getByRole('heading', {level: 1}).textContent;
  assert.equal(heading, "Gregorio Y. Zara's Todos", 'die Überschrift lautet ' + JSON.stringify(heading));
});

test('Das Bild liest src und alt aus person', () => {
  render(<TodoHeader />);
  const img = screen.getByRole('img');
  assert.equal(img.getAttribute('src'), 'gregorio-zara.jpg', 'das Bild hat src=' + JSON.stringify(img.getAttribute('src')));
  assert.equal(img.getAttribute('alt'), 'Gregorio Y. Zara', 'das Bild hat alt=' + JSON.stringify(img.getAttribute('alt')));
});

test('Das Bild ist 90px breit und hoch, aus person.imageSize', () => {
  render(<TodoHeader />);
  const {width, height} = screen.getByRole('img').style;
  assert.equal(width, '90px', 'das Bild hat die Breite ' + JSON.stringify(width));
  assert.equal(height, '90px', 'das Bild hat die Höhe ' + JSON.stringify(height));
});

test('Der Header verwendet person.theme als Style', () => {
  render(<TodoHeader />);
  const {backgroundColor, color} = screen.getByRole('banner').style;
  assert.equal(backgroundColor, 'black', 'der Header hat background-color ' + JSON.stringify(backgroundColor));
  assert.equal(color, 'pink', 'der Header hat color ' + JSON.stringify(color));
});

test('React gibt keine Warnungen aus', () => {
  const warnings = [];
  const original = console.error;
  console.error = (...args) => warnings.push(args.join(' '));
  try {
    render(<TodoHeader />);
  } finally {
    console.error = original;
  }
  assert.deepEqual(warnings, [], 'console.error beim Rendern');
});

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

style als String schreiben

export default function Title() {
  return <h1 style="color: red">Todos</h1>;
}

Was React ausgibt

The `style` prop expects a mapping from style properties to values, not a string.

Warum, und die Lösung

In React nimmt style ein Objekt, keinen CSS-Text, und ein String bricht das Rendern ab: Der Lauf gibt Uncaught Error mit dieser Meldung aus. Schreiben Sie das Objekt in doppelte Klammern, mit camelCase-Namen: <h1 style={{ color: 'red' }}>. Für background-color schreiben Sie backgroundColor.

<img> offen lassen, wie HTML es erlaubt

export default function Avatar() {
  return (
    <div>
      <img src="hedy.jpg" alt="Hedy Lamarr">
    </div>
  );
}

Was React ausgibt

error TS17008: JSX element 'img' has no corresponding closing tag.

Warum, und die Lösung

HTML lässt <img> offen, JSX verlangt aber, dass jedes Tag geschlossen wird, deshalb bricht die JSX-Umwandlung ab, und nichts läuft. Die ganze Zeile beginnt mit der Position, main.jsx(4,8). Schließen Sie das Tag mit einem Schrägstrich: <img src="hedy.jpg" alt="Hedy Lamarr" />. Dasselbe gilt für <br />, <hr /> und <input />.

for an einem Label schreiben

export default function TaskField() {
  return (
    <>
      <label for="task">Task</label>
      <input id="task" />
    </>
  );
}

Was React ausgibt

Invalid DOM property `for`. Did you mean `htmlFor`?

Warum, und die Lösung

for ist in JavaScript ein reserviertes Wort, deshalb heißt das Attribut in JSX htmlFor, nach der DOM-Eigenschaft. React 19 setzt for="task" trotzdem auf das Label, warnt aber, und der Runner des Kurses wertet jede Warnung als fehlgeschlagenen Lauf. Schreiben Sie <label htmlFor="task">. Dieselbe Art Korrektur nennt React für tabindex (tabIndex) und stroke-width (strokeWidth).

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

JSX: Markup und Logik zusammen, mit strengeren Regeln

Mit JSX schreiben Sie HTML-ähnliches Markup mitten in JavaScript, sodass eine Komponente Logik und Markup an einem Ort hält. Eingefügtes HTML braucht drei Änderungen. Geben Sie ein Wurzelelement zurück oder umschließen Sie Geschwister mit einem Fragment <>…</>, das auf der Seite keine Spur hinterlässt. Schließen Sie jedes Tag: <img /> und <br /> enden mit einem Schrägstrich, <li> braucht </li>. Schreiben Sie die meisten Attribute in camelCase: className, htmlFor, tabIndex, strokeWidth. Nur aria-* und data-* behalten ihre Bindestriche. Ein falscher Name wird trotzdem gerendert, aber React warnt und nennt die Korrektur.

Anführungszeichen übergeben Strings, Klammern JavaScript

Ein Attribut in Anführungszeichen ist ein String: alt="Hedy Lamarr". Geschweifte Klammern öffnen ein Fenster zu JavaScript: src={avatar} liest die Variable avatar, und jeder Ausdruck funktioniert, etwa {tasks.length} oder ein Aufruf wie {formatDate(today)}. Klammern funktionieren an genau zwei Stellen: als Text in einem Tag, <h1>{name}'s Todos</h1>, und direkt nach dem = eines Attributs. src="{avatar}" übergibt den Text {avatar}, und ein Tag-Name in Klammern, <{tag}>, lässt sich nicht übersetzen.

Doppelte Klammern sind ein Objekt in Klammern

Um ein Objekt zu übergeben, schreiben Sie es in die JSX-Klammern, das ergibt zwei Paare: style={{ backgroundColor: 'black', color: 'pink' }}. Das Style-Objekt verwendet camelCase-Namen, aus background-color in CSS wird also backgroundColor, und eine bloße Zahl wie fontSize: 24 bedeutet 24px. Ein Style-String, style="color: red", ist in React ein Fehler. Sie können Werte auch in einem Objekt ablegen, person.theme, und es übergeben: style={person.theme}. Als Text lässt sich ein Objekt aber nicht zeigen: {person} in einem Tag ist ein Fehler; zeigen Sie {person.name}.

Quellen

Zuletzt geprüft am 5. Oktober 2026