Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

Formular-Validierung in React (ohne Bibliothek)

Form Validation in React

~12 Min. Lesezeit Zuletzt aktualisiert am 8. August 2026

Jetzt bauen wir unser erstes echtes Formular: eine Produktbewertung mit Name, Sternebewertung und Kommentar. In diesem Kapitel validieren wir "von Hand", mit reinem React-State – im nächsten Kapitel lernen Sie dann eine Bibliothek kennen, die vieles davon automatisiert.

Das Prinzip: Fehler als eigener State

Neben dem State für die Formularwerte selbst führen wir einen ZWEITEN State-Wert für Validierungsfehler – meist ein Objekt, dessen Schlüssel den Feldnamen entsprechen:

const [values, setValues] = useState({ name: '', comment: '' });
const [errors, setErrors] = useState({});

function validate(values) {
  const newErrors = {};
  if (values.name.trim() === '') {
    newErrors.name = 'Bitte geben Sie Ihren Namen ein.';
  }
  if (values.comment.trim().length < 10) {
    newErrors.comment = 'Der Kommentar muss mindestens 10 Zeichen lang sein.';
  }
  return newErrors;
}

components/ReviewForm.jsx anlegen

Legen Sie src/components/ReviewForm.jsx an – ein vollständiges, manuell validiertes Formular mit Name, Sternebewertung (1–5) und Kommentar:

src/components/ReviewForm.jsx
import { useState } from 'react';

const ANFANGSWERTE = { name: '', rating: 5, comment: '' };

function validate(values) {
  const errors = {};
  if (values.name.trim() === '') {
    errors.name = 'Bitte geben Sie Ihren Namen ein.';
  }
  if (values.comment.trim().length < 10) {
    errors.comment = 'Der Kommentar muss mindestens 10 Zeichen lang sein.';
  }
  return errors;
}

function ReviewForm({ onSubmitReview }) {
  const [values, setValues] = useState(ANFANGSWERTE);
  const [errors, setErrors] = useState({});

  function handleChange(event) {
    const { name, value } = event.target;
    setValues({ ...values, [name]: value });
  }

  function handleSubmit(event) {
    event.preventDefault();
    const validationErrors = validate(values);
    setErrors(validationErrors);

    if (Object.keys(validationErrors).length === 0) {
      onSubmitReview(values);
      setValues(ANFANGSWERTE);
    }
  }

  return (
    <form onSubmit={handleSubmit} className="review-form">
      <div className="form-field">
        <label htmlFor="name">Name</label>
        <input
          id="name"
          name="name"
          value={values.name}
          onChange={handleChange}
        />
        {errors.name && <p className="form-error">{errors.name}</p>}
      </div>

      <div className="form-field">
        <label htmlFor="rating">Bewertung</label>
        <select id="rating" name="rating" value={values.rating} onChange={handleChange}>
          {[5, 4, 3, 2, 1].map((stern) => (
            <option key={stern} value={stern}>{stern} {stern === 1 ? 'Stern' : 'Sterne'}</option>
          ))}
        </select>
      </div>

      <div className="form-field">
        <label htmlFor="comment">Kommentar</label>
        <textarea
          id="comment"
          name="comment"
          value={values.comment}
          onChange={handleChange}
        />
        {errors.comment && <p className="form-error">{errors.comment}</p>}
      </div>

      <button type="submit">Bewertung abschicken</button>
    </form>
  );
}

export default ReviewForm;

Ein paar Details, die hier zusammenspielen: name="name"/name="rating" auf jedem Feld erlaubt EINEN gemeinsamen handleChange für alle Felder – event.target.name verrät, welches Feld sich geändert hat, und {{ ...values, [name]: value }} ("computed property name") aktualisiert gezielt nur dieses eine Feld im Objekt, ohne die anderen zu verlieren.

event.preventDefault() ist entscheidend: Ohne diese Zeile würde der Browser beim Absenden eines <form> standardmäßig die komplette Seite neu laden (der klassische, vor-JavaScript-Weg, Formulare zu verarbeiten) – das würde unseren gesamten React-State verlieren.

Zwei kleine, aber wichtige HTML-Unterschiede

HTMLReact
<label for="name"><label htmlFor="name">for ist wie class ein reserviertes JS-Wort
<option selected>ausgewählte Option wird über value am <select> selbst gesteuert, nicht am <option>

Tipp: Diese Datei ist noch nicht im Browser sichtbar – wir binden sie erst in Kapitel 16 (Real-World Forms) in unsere echte Seite ein, sobald wir mit Routing (Phase 4) auch eine eigene Produktdetail-Unterseite dafür haben.