Zum Inhalt springen

Events in React

Bisher waren unsere Komponenten rein darstellend — sie empfangen Props und rendern JSX. Aber eine echte Anwendung muss auf Benutzerinteraktionen reagieren: Klicks, Eingaben, Formulare. Dafür gibt es Event-Handler.

Ein Event-Handler ist eine Funktion, die React aufruft, wenn ein bestimmtes Event eintritt. Du übergibst sie als Prop an ein JSX-Element:

function App() {
function handleClick() {
alert("Button wurde geklickt!");
}
return <button onClick={handleClick}>Klick mich</button>;
}

Drei Dinge sind hier wichtig:

  1. Die Funktion wird definierthandleClick ist eine normale Funktion innerhalb der Komponente.
  2. Die Funktion wird übergeben, nicht aufgerufenonClick={handleClick} ohne (). Mit () würde die Funktion sofort beim Rendern ausgeführt, nicht erst beim Klick.
  3. onClick statt onclick — React verwendet camelCase für Event-Props.

In React hat sich die Konvention handle + Eventname etabliert:

function handleClick() { /* ... */ }
function handleChange() { /* ... */ }
function handleSubmit() { /* ... */ }
function handleMouseEnter() { /* ... */ }

Das ist eine Konvention, keine Pflicht. Für einfache Fälle oder Inline-Handler musst du dich nicht daran halten — niemand benennt jede anonyme Arrow-Function nach diesem Schema. Die Konvention hilft vor allem, wenn eine Komponente mehrere Handler hat und du auf einen Blick sehen willst, was wozu gehört.

Für kurze Handler kannst du die Funktion direkt inline schreiben:

// Arrow Function
<button onClick={() => alert("Klick!")}>Klick mich</button>
// Auch mehrzeilig
<button onClick={() => {
console.log("Klick!");
alert("Klick!");
}}>
Klick mich
</button>

Inline-Handler sind praktisch bei kurzer Logik. Bei mehr als zwei Zeilen lohnt es sich, die Funktion herauszuziehen — nicht wegen einer Regel, sondern weil es lesbarer wird.

Jeder Event-Handler bekommt automatisch ein Event-Objekt als erstes Argument. Schau es dir mit console.log an:

function App() {
function handleClick(event) {
console.log(event);
}
return <button onClick={handleClick}>Klick mich</button>;
}

In der Konsole siehst du ein SyntheticBaseEventnicht das native Browser-Event. React wickelt alle Events in eigene Objekte ein, die über alle Browser hinweg identisch funktionieren. Du kannst sie aber genauso verwenden wie native Events:

function handleClick(event) {
console.log(event.target); // das geklickte DOM-Element
console.log(event.clientX); // X-Position des Klicks
console.log(event.nativeEvent); // das originale Browser-Event
}

Das SyntheticBaseEvent hat die gleichen Properties und Methoden wie das native Event (target, preventDefault(), stopPropagation(), …) — mit dem Unterschied, dass es in jedem Browser gleich aussieht.

Wenn du in reinem JavaScript (ohne TypeScript) arbeitest, kannst du den Event-Typ mit JSDoc dokumentieren:

/**
* @param {React.MouseEvent<HTMLButtonElement>} event
*/
function handleClick(event) {
console.log(event.clientX);
}

Dein Editor (z.B. VS Code) bietet dir dann Autocomplete und Typprüfung für alle Properties des Events. Woher kommt der Typ? React definiert eigene Event-Interfaces wie React.MouseEvent, React.ChangeEvent, React.FormEvent usw. — passend zum jeweiligen Event. Der Typ-Parameter in spitzen Klammern (z.B. <HTMLButtonElement>) gibt an, auf welchem DOM-Element das Event ausgelöst wird.

HTML-Elemente wie <button> oder <input> haben eingebaute Event-Props (onClick, onChange, …). Aber was ist mit eigenen Komponenten?

Eigene Komponenten haben keine eingebauten Events. Wenn du <MeinButton onClick={...} /> schreibst, ist onClick einfach ein Prop wie jeder andere — ein Callback, den die Komponente intern an ein HTML-Element weitergibt:

function MeinButton({ onClick, children }) {
return <button onClick={onClick}>{children}</button>;
}
function App() {
return (
<MeinButton onClick={() => alert("Klick!")}>
Klick mich
</MeinButton>
);
}

MeinButton empfängt onClick als Prop und gibt es an den nativen <button> weiter. Das Event wird also nicht von MeinButton ausgelöst, sondern vom <button> darin.

Für Event-Props eigener Komponenten gibt es eine klare Konvention:

  • Props beginnen mit on: onClick, onDelete, onSearch
  • Handler beginnen mit handle: handleClick, handleDelete, handleSearch
function SucheingabeFeld({ onSearch }) {
function handleChange(event) {
onSearch(event.target.value);
}
return <input onChange={handleChange} placeholder="Suchen..." />;
}
function App() {
function handleSearch(suchbegriff) {
console.log("Suche nach:", suchbegriff);
}
return <SucheingabeFeld onSearch={handleSearch} />;
}

Beachte den Unterschied: SucheingabeFeld bekommt onSearch (was passieren soll) und entscheidet intern, wann es aufgerufen wird (bei onChange des Inputs). Die Elternkomponente definiert das Verhalten, die Kindkomponente steuert den Zeitpunkt.

Events in React „blubbern” nach oben — genau wie im DOM. Wenn du auf ein Element klickst, wird das Event an alle Elternelemente weitergegeben:

function App() {
return (
<div onClick={() => console.log("div geklickt")}>
<button onClick={() => console.log("button geklickt")}>
Klick mich
</button>
</div>
);
}

Ein Klick auf den Button löst beide Handler aus:

  1. "button geklickt" (das direkte Ziel)
  2. "div geklickt" (das Event blubbert zum <div> hoch)

Um das zu verhindern, rufst du event.stopPropagation() auf:

function App() {
return (
<div onClick={() => console.log("div geklickt")}>
<button onClick={(event) => {
event.stopPropagation();
console.log("button geklickt");
}}>
Klick mich
</button>
</div>
);
}

Jetzt wird nur "button geklickt" ausgegeben — das Event erreicht den <div> nicht mehr.

Manche HTML-Elemente haben ein eingebautes Verhalten. Zum Beispiel lädt ein <form> beim Absenden die Seite neu. Das willst du in einer React-App fast nie:

function Anmeldeformular() {
function handleSubmit(event) {
event.preventDefault();
console.log("Formular abgeschickt — ohne Seitenneuladen");
}
return (
<form onSubmit={handleSubmit}>
<input type="text" placeholder="Benutzername" />
<button type="submit">Anmelden</button>
</form>
);
}

event.preventDefault() verhindert das Standard-Verhalten des Browsers — die Seite wird nicht neu geladen, und du kannst das Formular in JavaScript verarbeiten.

MethodeWas sie tut
event.stopPropagation()Verhindert, dass das Event an Elternelemente weitergegeben wird
event.preventDefault()Verhindert das Standard-Verhalten des Browsers (z.B. Seitenneuladen bei <form>)

Beide Methoden sind unabhängig voneinander — du kannst sie einzeln oder zusammen verwenden.

KonzeptBeschreibung
Event-HandlerFunktionen, die als Props übergeben werden: onClick={handleClick}
Übergeben, nicht aufrufenonClick={handleClick} — ohne ()
Inline-HandleronClick={() => alert("Klick!")} — für kurze Logik
Event-ObjektSyntheticBaseEvent — Reacts browserübergreifender Event-Wrapper
Eigene KomponentenEvent-Props sind Callbacks: onSearch, onDelete
PropagationEvents blubbern nach oben — stopPropagation() verhindert das
Default-VerhaltenpreventDefault() verhindert Browser-Standardaktionen