React-Komponenten sind die Grundbausteine jeder React-Anwendung. Im Kern ist eine Komponente einfach eine JavaScript-Funktion, die JSX zurückgibt — eine HTML-ähnliche Syntax, die zur Laufzeit zu echten DOM-Elementen wird. Komponenten lassen sich beliebig verschachteln, mit props von außen konfigurieren und mit useState um internen Zustand erweitern. Dieser Artikel zeigt den minimalen Aufbau, die wichtigsten Regeln (ein umgebendes Element, PascalCase-Naming) und wie sich Logik sauber in den Funktionskörper integrieren lässt.
Minimale Struktur
Eine React-Komponente ist im Wesentlichen eine Funktion mit Großbuchstaben am Anfang, die JSX zurückgibt. Der Großbuchstabe ist Pflicht — React unterscheidet daran zwischen eigenen Komponenten (<MyButton />) und nativen HTML-Tags (<button />).
function MinimalComponent() {
return <p>Hello world</p>;
}
export default MinimalComponent;Diese Komponente wird in der main.jsx (oder in einer anderen Komponente) eingebunden. Erst dann erscheint sie im Browser:
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import MinimalComponent from './MinimalComponent.jsx';
createRoot(document.getElementById('root')).render(
<StrictMode>
<MinimalComponent />
</StrictMode>,
);Das Ergebnis: Hello world im Browser.
Erklärung im Detail:
function MinimalComponent()— eine ganz normale JavaScript-Funktion mit PascalCase-Namen.return <p>...</p>— JSX als Rückgabewert, HTML-ähnliche Syntax mit JavaScript-Power.export default— die Funktion wird exportiert, damit andere Dateien sie importieren können.
Genauso erlaubt ist die Arrow-Function-Form — heute der weiter verbreitete Stil:
const MinimalComponent = () => {
return <p>Hello world</p>;
};
export default MinimalComponent;Funktional identisch — Geschmacks- und Konventions-Frage. Viele Teams setzen einen Linter wie ESLint mit der Regel react/function-component-definition ein, um konsistent zu bleiben.
Ein einzelnes umgebendes Element
JSX erlaubt pro Komponente nur ein umgebendes Element. Mehrere Geschwister auf oberster Ebene sind ein Syntax-Fehler.
const Card = () => {
return (
<div>
<h2>Titel</h2>
<p>Beschreibung</p>
</div>
);
};Wenn man den zusätzlichen <div> vermeiden will, gibt es Fragments — entweder als <React.Fragment> oder in der Kurzform <>...</>:
const Card = () => {
return (
<>
<h2>Titel</h2>
<p>Beschreibung</p>
</>
);
};Fragments rendern keinen zusätzlichen DOM-Knoten — ideal in Tabellen-Zeilen, Listen-Items oder Layout-Komponenten, in denen ein Wrapper-<div> das CSS brechen würde. Details im eigenen Artikel zu Fragments.
Dynamische Werte mit {}
In JSX werden JavaScript-Ausdrücke in geschweifte Klammern gesetzt. Alles innerhalb von {...} wird als JS evaluiert und das Ergebnis eingefügt.
const Welcome = () => {
const username = 'Anna';
const stunde = new Date().getHours();
return (
<p>
Hi {username}, es ist {stunde} Uhr.
{stunde >= 18 && ' Guten Abend!'}
</p>
);
};Innerhalb der Klammern kann jeder Ausdruck stehen — Variablen, Funktions-Aufrufe, Ternaries, &&-Short-Circuit. Statements (if, for) dagegen nicht — wer Branching im JSX braucht, nutzt Ternary oder Conditional Rendering.
Components ohne JSX
React für Browser besteht aus zwei Paketen: react und react-dom. JSX ist nur Syntax-Zucker für React.createElement(...)-Aufrufe — die Build-Toolchain (Babel/SWC/esbuild) transformiert JSX zur Build-Zeit.
import React from 'react';
const PlainComponent = () => {
return React.createElement(
'a',
{ href: 'https://google.com' },
'Go to Google'
);
};
export default PlainComponent;Verschachtelte Elemente werden als weitere createElement-Aufrufe in der Children-Position übergeben:
const Alert = () => {
return React.createElement(
'div',
{},
React.createElement('h2', {}, 'Das ist ein Alert')
);
};In der Praxis schreibt das niemand so — JSX ist deutlich lesbarer. Aber zu wissen, was unter der Haube passiert, hilft beim Debuggen und beim Verständnis von Tools, die JSX-Output transformieren.
Komponenten mit Logik
Eine Komponente ist eine ganz normale Funktion — alles, was vor dem return steht, ist regulärer JavaScript-Code. Variablen-Deklarationen, Funktions-Definitionen, Berechnungen, Hooks-Aufrufe.
const Greeting = () => {
const username = 'John';
const greeting = (h) => h < 12 ? 'Guten Morgen' : 'Guten Tag';
return (
<p>{greeting(new Date().getHours())}, {username}!</p>
);
};Wichtig: alles, was in der Komponenten-Funktion deklariert wird, wird bei jedem Re-Render neu erzeugt. Funktionen, die referenzielle Identität brauchen (z.B. für useEffect-Dependencies oder React.memo), gehören in useCallback — siehe das Hooks-Kapitel.
Naming und Datei-Organisation
Best-Practice-Konventionen, an die sich praktisch alle React-Codebases halten:
- PascalCase für Komponenten-Namen:
UserCard,LoginForm,Header. - Eine Komponente pro Datei — Dateiname spiegelt den Komponenten-Namen.
- camelCase für Hooks, Helper-Funktionen, Variablen:
useUser,formatDate. - Default-Export für die Haupt-Komponente einer Datei, optional named exports für Helfer.
// UserCard.jsx
export default function UserCard({ user }) {
return <div>{user.name}</div>;
}
// App.jsx
import UserCard from './UserCard';Ordnerstruktur ist Geschmackssache. Drei verbreitete Stile:
- Flat: alle Komponenten im selben
src/components/-Verzeichnis. Funktioniert für kleine Projekte. - Feature-based: pro Feature ein Ordner mit allen zugehörigen Komponenten, Hooks und Tests. Skalierbar.
- Atomic Design: Komponenten nach Granularität gruppieren (atoms, molecules, organisms). Strenger, oft Over-Engineering.
Interessantes
Komponenten-Namen MÜSSEN mit Großbuchstaben beginnen.
<MyButton /> wird als Komponente interpretiert, <mybutton /> als unbekanntes HTML-Tag. Das ist eine harte React-Regel — keine Konvention. Ohne Großbuchstaben rendert React still ein leeres HTML-Element.
JSX braucht genau ein umgebendes Element.
Mehrere Geschwister auf Top-Ebene sind ein Syntax-Fehler. Lösung: ein Container (<div>) oder ein Fragment <>...</>. Fragment vermeidet den extra-DOM-Knoten.
Geschweifte Klammern nehmen Expressions, keine Statements.
In {...} kann jede Expression stehen — Variable, Aufruf, Ternary. Aber if, for, switch sind Statements und nicht erlaubt. Wer Branches braucht: Ternary, &&-Short-Circuit, oder Logik in eine Helper-Funktion auslagern.
Komponenten sind reine Funktionen — keine Side-Effects im Body.
Was vor dem return steht, läuft bei jedem Render. Side-Effects (Fetch, Subscribe, DOM-Manipulation) gehören in useEffect. Eine console.log im Body ist okay zum Debuggen, aber kein Production-Code.
Funktions-Komponenten haben keinen this-Kontext.
Anders als Klassen-Komponenten gibt es kein this — alle Werte kommen über Parameter (props) und Hooks (useState, useContext). Die meisten this-Fallen aus Klassen-Komponenten verschwinden damit automatisch.
JSX-Attribute nutzen camelCase statt HTML-kebab-case.
onclick wird zu onClick, tabindex zu tabIndex, readonly zu readOnly. Class ist reserviert in JS und wird zu className. for (Label) wird zu htmlFor.
Weiterführende Ressourcen
Externe Quellen
- Your First Component – react.dev
- Writing Markup with JSX – react.dev
- JavaScript in JSX with Curly Braces – react.dev