
HTML zu JSX: Die 7 Fallstricke, ueber die jeder React-Anfaenger stolpert
📷 Pexels / PexelsHTML zu JSX: Die 7 Fallstricke, ueber die jeder React-Anfaenger stolpert
className, htmlFor, selbstschliessende Tags, Inline-Stile -- HTML-zu-JSX-Konvertierung steckt voller subtiler Fallen. Lerne sie einmal und debugge sie nie wieder.
Es gibt ein Initiationsritual, das fast jedem Entwickler beim Erlernen von React widerfaehrt. Sie haben einen schoenen Chunk HTML -- vielleicht aus einem Design-Handoff, einem statischen Template oder etwas, das Sie aus einem alten Projekt kopiert haben -- und fuegen ihn direkt in eine Komponente ein. Dann beginnen die Fehler.
Warning: Invalid DOM property `class`. Did you mean `className`?
Dann noch einer.
Warning: Invalid DOM property `for`. Did you mean `htmlFor`?
Dann moeglicherweise ein Parse-Fehler von einem nicht geschlossenen <img>- oder <input>-Tag. Wenn Sie sich durch sechs Warnungen gescrollt haben, fragen Sie sich, warum React kein normales HTML akzeptieren konnte. Eine faire Frage, eigentlich.
Warum JSX nicht einfach HTML ist
Die kurze Antwort: JSX sieht aus wie HTML, ist aber JavaScript in Verkleidung. Wenn Babel Ihre Komponente verarbeitet, wird jedes <div className="wrapper"> zu React.createElement('div', { className: 'wrapper' }). Diese Transformation macht JSX so maechtig -- aber das ist auch, warum Sie HTML nicht wortwortlich kopieren koennen.
HTML ist eine Auszeichnungssprache. Sie hat eigene Parsing-Regeln, und Browser sind dafuer ausgelegt, nachsichtig damit umzugehen. JSX ist JavaScript-Syntax, die zufaellig HTML aehnelt. JavaScript-Parser sind nicht nachsichtig. Sie haben reservierte Schluesselwoerter, strenge Syntaxregeln und keine Toleranz fuer Mehrdeutigkeit.
Diese Spannung -- die Lockerheit von HTML gegenueber der Strenge von JavaScript -- ist die Grundursache jedes Konvertierungsfehlers, dem Sie begegnen werden.
Die Transformationen, die Sie kennen muessen
1. class → className
Das ist das, was jeder zuerst lernt, normalerweise durch eine Warnung.
<!-- HTML -->
<div class="container main-content">
<p class="text-gray">Hello world</p>
</div>
// JSX
<div className="container main-content">
<p className="text-gray">Hello world</p>
</div>
Der Grund ist einfach: class ist ein reserviertes Schluesselwort in JavaScript (so definiert man ES6-Klassen). Wenn JSX class als Attribut erlauben wuerde, wuerde der JavaScript-Parser verwirrt. className ist ein duenner Workaround, der direkt auf die DOM-Eigenschaft desselben Namens abbildet -- wenn React auf das echte DOM rendert, setzt es die className-Eigenschaft, die dem HTML-class-Attribut entspricht. Das Endergebnis ist identisch; nur die Syntax aendert sich.
2. for → htmlFor
Gleiche Logik. for ist ein reserviertes Schluesselwort in JavaScript (so schreibt man For-Schleifen). Labels in Formularen verwenden for, um mit der id eines Inputs verbunden zu werden:
<!-- HTML -->
<label for="email">Email address</label>
<input type="email" id="email" />
// JSX
<label htmlFor="email">Email address</label>
<input type="email" id="email" />
Viele Entwickler merken sich className, vergessen aber htmlFor. Wird weniger haeufig diskutiert, wirft aber die gleiche Art von Warnung, wenn man es vergisst.
3. Selbstschliessende Void-Elemente
In HTML benoetigen Void-Elemente -- Tags, die keine Kinder haben koennen -- keinen schliessenden Schraegstrich. Browser kommen damit klar:
<!-- Valid HTML -->
<img src="photo.jpg" alt="A photo">
<input type="text" name="username">
<br>
<hr>
<meta charset="UTF-8">
JSX erfordert, dass jedes Element explizit geschlossen wird. Entweder fuegt man den schliessenden Schraegstrich vor dem > hinzu oder ein separates schiessendes Tag:
// JSX - muss sich selbst schliessen
<img src="photo.jpg" alt="A photo" />
<input type="text" name="username" />
<br />
<hr />
<meta charSet="UTF-8" />
Beachten Sie, dass ich auch charset in charSet im letzten Beispiel geaendert habe. Das ist das camelCase-Muster, das als naechstes behandelt wird.
4. CamelCase-Attribute
HTML-Attribute sind nicht case-sensitiv. JSX-Attributnamen werden DOM-Eigenschaften zugeordnet, und DOM-Eigenschaften folgen camelCase-Konventionen. Die haeufigsten, denen Sie begegnen werden:
| HTML | JSX |
|---|---|
onclick | onClick |
onchange | onChange |
tabindex | tabIndex |
maxlength | maxLength |
readonly | readOnly |
autocomplete | autoComplete |
autofocus | autoFocus |
crossorigin | crossOrigin |
charset | charSet |
Event-Handler sind wahrscheinlich die am haeufigsten vorkommenden. HTML-Event-Attribute verwenden ausschliesslich Kleinbuchstaben:
<!-- HTML -->
<button onclick="handleClick()">Click me</button>
<input onchange="handleChange(event)" />
In JSX sind sie camelCase und Sie uebergeben eine Funktionsreferenz (keinen String):
// JSX
<button onClick={handleClick}>Click me</button>
<input onChange={handleChange} />
Der letzte Punkt -- eine Funktionsreferenz uebergeben statt eines String-Aufrufs -- ist ein wichtiger Unterschied. In HTML onclick ist der Wert ein auszufuehrender JavaScript-String. In JSX onClick ist der Wert ein JavaScript-Ausdruck (normalerweise eine Funktionsreferenz). Deshalb verwendet JSX geschweifte Klammern {} um den Wert statt Anfuehrungszeichen.
5. Inline-Stile als JavaScript-Objekte
Das ueberrascht Menschen beim ersten Mal. HTML-Inline-Stile sind Strings:
<!-- HTML -->
<div style="color: red; font-size: 16px; margin-top: 8px;">
Styled text
</div>
JSX-Inline-Stile sind JavaScript-Objekte, was bedeutet:
- Doppelte geschweifte Klammern (ein Paar fuer den JSX-Ausdruck, eines fuer das Objektliteral)
- Eigenschaftsnamen in camelCase
- Werte als Strings oder Zahlen (Zahlen fuer Pixel-Werte koennen optional schlichte Zahlen sein)
// JSX
<div style={{ color: 'red', fontSize: '16px', marginTop: '8px' }}>
Styled text
</div>
Die camelCase-Regel gilt auch hier: font-size wird zu fontSize, margin-top wird zu marginTop, background-color wird zu backgroundColor. Jede mit Bindestrich versehene CSS-Eigenschaft wird camelCase.
6. Kommentare
In HTML schreibt man <!-- comment -->. In JSX funktionieren HTML-Kommentare nicht. Sie muessen JavaScript-Kommentare innerhalb eines JSX-Ausdrucks verwenden:
<!-- HTML comment -->
<div>
<!-- This is a comment -->
<p>Content</p>
</div>
{/* JSX comment */}
<div>
{/* This is a comment */}
<p>Content</p>
</div>
Sie koennen auch // fuer einzeilige Kommentare verwenden, aber nur innerhalb der geschweiften Klammern oder im regulaeren JavaScript-Code -- nicht direkt im JSX-Markup.
Weniger offensichtliche Fallstricke
Boolean-Attribute verhalten sich anders
In HTML impliziert das Vorhandensein eines Attributs true fuer Boolean-Attribute:
<!-- HTML - diese sind gleichwertig -->
<input disabled>
<input disabled="true">
<input disabled="disabled">
In JSX koennen Boolean-Attribute als Kurzschreibweise geschrieben werden (wie HTML), aber die explizite Form sieht anders aus:
// JSX - diese sind alle gleichwertig
<input disabled />
<input disabled={true} />
Was in JSX vermieden werden sollte, ist disabled="true" (mit Anfuehrungszeichen), weil das den String "true" anstelle des Booleans true uebergibt. React rendert es moeglicherweise korrekt, aber es ist nicht idiomatisch und kann bei einigen Komponenten Probleme verursachen.
Das key-Prop in Listen
Wenn Sie HTML-Listen in JSX konvertieren und ueber Daten mappen, benoetigt React ein key-Prop fuer jedes Element. Das ist kein HTML-zu-JSX-Konvertierungsproblem per se -- es gilt nur, wenn Sie Elemente dynamisch generieren -- aber es ist gut zu wissen, bevor Sie die Warnung erhalten:
// React warnt ohne key
{items.map((item) => (
<li key={item.id}>{item.name}</li>
))}
SVG-Attribute
SVG hat seine eigene Reihe von Attributbenennungs-Eigenheiten. In HTML/SVG schreibt man vielleicht fill-opacity, stroke-width, clip-path. In JSX werden diese zu fillOpacity, strokeWidth, clipPath. Wenn Sie Inline-SVG aus einer Icon-Bibliothek oder einem Design-Tool einfuegen, muss man etwas aufraumen.
tabindex vs tabIndex
Leicht zu uebersehen. Wenn Sie barrierefreie Komponenten bauen und tabindex manuell setzen, denken Sie daran, dass es in JSX zu tabIndex wird. Das zu verpassen wirft nicht immer einen Fehler -- React rendert es moeglicherweise trotzdem -- aber es ist ein stiller Unterschied, der das Verhalten beeinflussen koennte.
Wann man einen automatischen Konverter verwendet
Wenn Sie einen grossen Block HTML haben -- eine Komponente aus einem Design-System, ein Template, das Sie von einer Nicht-React-Codebasis migrieren, oder ein Snippet aus einer Online-Quelle -- ist die Verwendung eines Konverters die praktische Wahl. Jedes class manuell durch className zu ersetzen und jeden mit Bindestrich versehenen Event-Handler ist muehsam und fehleranfaellig.
Der ToolPal HTML-zu-JSX-Konverter behandelt die Standard-Transformationen automatisch: class → className, for → htmlFor, Style-Strings → Style-Objekte, selbstschliessende Void-Elemente, camelCase-Attribute. Sie fuegen Ihr HTML ein, erhalten gueltiges JSX zurueck und machen weiter.
Wo automatische Konverter nicht helfen koennen, sind strukturelle Entscheidungen. Das Konvertieren von 500 Zeilen HTML in eine einzige JSX-Return-Anweisung gibt Ihnen keine gut architekturierte Komponente -- es gibt Ihnen einen konvertierten Klumpen. Fuer alles Substantielle behandelt der Konverter die Syntax, aber Sie muessen immer noch entscheiden, wie das Ergebnis in kleinere Komponenten aufgeteilt werden soll, wo Props hartcodierte Werte ersetzen sollten und welche Teile dynamisch sein sollen.
Verwenden Sie den Konverter fuer die mechanische Transformation. Verwenden Sie Ihren Kopf fuer die Architektur.
Wann man JSX von Grund auf schreibt
Wenn Sie eine neue Komponente bauen und das Design in Ihrem Kopf haben (oder in einem Mockup), ist JSX direkt zu schreiben oft schneller als HTML zu schreiben und es dann zu konvertieren. Sie schreiben von Anfang an className, vergessen nicht, Ihre Void-Elemente zu schliessen, und enden nicht mit Style-Strings, die konvertiert werden muessen.
Die Faelle, in denen Konvertierung wirklich hilft:
Migration von einem Nicht-React-Projekt. Wenn Sie vorhandene HTML-Templates haben -- von einer einfachen HTML/CSS-Seite, einer Rails-App oder einem Jinja-Template -- sparen Konvertierungstools echte Zeit.
Arbeit von einem Design-Handoff. Designer exportieren oft HTML-Markup oder stellen Snippets bereit. Das durch einen Konverter laufen zu lassen ist schneller als es neu einzutippen.
Einfuegen von Drittanbieter-Snippets. Code-Beispiele aus Dokumentationen, Stack-Overflow-Antworten oder Tutorials sind oft in HTML geschrieben. Eine schnelle Konvertierung gibt Ihnen nutzbares JSX ohne manuelle Bearbeitung.
Grosse Formulare. Formulare mit Dutzenden von Eingaben, Labels und Fieldsets sind muehsam von Hand zu schreiben. Fuegen Sie die HTML-Struktur ein, konvertieren Sie sie, dann ersetzen Sie die hardcodierten Werte durch Props und State.
Ein realistisches Konvertierungsbeispiel
Hier ist eine kleine Karten-Komponente in HTML:
<div class="card" id="product-card">
<img src="/product.jpg" alt="Product photo" class="card-image">
<div class="card-body">
<h2 class="card-title">Product Name</h2>
<p class="card-description" style="color: #666; font-size: 14px;">
A short description of the product.
</p>
<label for="quantity">Quantity</label>
<input type="number" id="quantity" min="1" max="99" readonly>
<button class="btn btn-primary" onclick="addToCart()">Add to Cart</button>
</div>
</div>
Nach der Konvertierung:
<div className="card" id="product-card">
<img src="/product.jpg" alt="Product photo" className="card-image" />
<div className="card-body">
<h2 className="card-title">Product Name</h2>
<p className="card-description" style={{ color: '#666', fontSize: '14px' }}>
A short description of the product.
</p>
<label htmlFor="quantity">Quantity</label>
<input type="number" id="quantity" min="1" max="99" readOnly />
<button className="btn btn-primary" onClick={addToCart}>Add to Cart</button>
</div>
</div>
Beachten Sie jede Aenderung:
- Alle
class→className <img>und<input>sind selbstschliessend mit/>style-String → Style-Objekt mit camelCase-Eigenschaftenfor→htmlForreadonly→readOnlyonclick="addToCart()"→onClick={addToCart}(Funktionsreferenz, keine Klammern)
Der letzte Punkt ueber den Event-Handler ist es wert, betont zu werden. In der HTML-Version ist onclick="addToCart()" ein String, der ausgewertet wird. Wenn Sie versehentlich onClick="addToCart()" in JSX schreiben, wird React einen Fehler ausgeben, dass Event-Handler Funktionen sein muessen, keine Strings. Und wenn Sie onClick={addToCart()} (mit Klammern) schreiben, rufen Sie die Funktion sofort beim Rendern statt beim Klicken auf. Beides sind haeufige Anfaengerfehler.
Einige Dinge, die Konverter nicht koennen
Dynamischer Inhalt. Ein Konverter weiss nicht, dass Product Name zu {product.name} werden sollte. Er konvertiert die Struktur, aber Sie muessen statische Werte selbst durch Props und State ersetzen.
Event-Handler-Logik. onclick="addToCart()" wird zu onClick={addToCart} konvertiert, aber addToCart muss noch irgendwo in Ihrer Komponente definiert werden. Der Konverter gibt Ihnen die Attributsyntax; die Funktion liegt in Ihrer Verantwortung.
Bedingte Darstellung. HTML hat kein Konzept von "dieses Element nur anzeigen, wenn X wahr ist". Dieses Muster fuegen Sie waehrend des Komponentisierungsschritts hinzu, nicht etwas, das ein Konverter aus statischem Markup schliessen kann.
Mehrere Root-Elemente. Wenn Ihr HTML-Snippet zwei Geschwister-Elemente auf der obersten Ebene hat, hat das konvertierte JSX ebenfalls zwei Geschwister-Elemente -- was in einer Komponenten-Return-Anweisung ungueltig ist. Sie muessen sie in ein <div> oder <>...</>-Fragment einwickeln.
HTML-zu-JSX-Konvertierung ist eines dieser Dinge, das nervig anfuehlt, bis es zur zweiten Natur wird. Nach einigen Wochen React-Schreiben werden Sie automatisch className eingeben, ohne nachzudenken. Sie werden Ihre <img />-Tags reflexartig schliessen. Aber bis sich dieses Muskelgedaechtnis entwickelt, machen Tools wie der ToolPal HTML-zu-JSX-Konverter den Uebergang schneller und weniger frustrierend.
Die echte Faehigkeit ist nicht das Auswendiglernen der Syntaxunterschiede -- es ist das Verstehen, warum sie existieren. Sobald Sie verstehen, dass JSX JavaScript ist, hoeren die Regeln auf, willkuerlich zu wirken, und beginnen Sinn zu ergeben.