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 />).

TypeScript MinimalComponent.jsx
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:

TypeScript main.jsx
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:

TypeScript ArrowComponent.jsx
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.

TypeScript MitContainer.jsx
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 <>...</>:

TypeScript MitFragment.jsx
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.

TypeScript DynamischeWerte.jsx
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.

TypeScript OhneJSX.jsx
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:

TypeScript VerschachteltOhneJSX.jsx
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.

TypeScript MitLogik.jsx
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.
TypeScript UserCard.jsx
// 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 &#123;...&#125; 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

/ Weiter

Zurück zu Components

Zur Übersicht