Zie het in actie — typ iets

In React werken forms met controlled inputs: de input en state praten elke toetsaanslag met elkaar. Typ in het veld en kijk hoe de cyclus oplicht.

Uncontrolled (kapot) Controlled (goed)
Input
value={name}   onChange={e => setName(e.target.value)}
State (name)
leeg
1
Gebruiker typt
keystroke
2
onChange firet
e.target.value
3
setState
setName(...)
4
Re-render
value={name}
⚠️ Uncontrolled modus: de input bewaart zijn eigen waarde, state weet van niks.

Wat je net zag: Elke toetsaanslag triggert dezelfde 4 stappen: toets → onChange → setState → re-render. De waarde op je scherm komt uit de state, niet uit de input zelf. Zet de toggle op "Uncontrolled" en typ — de state blijft leeg, bewijs dat de twee dan niet meer praten.

Basis Form

Hierboven zag je de cyclus visueel. In code ziet hetzelfde voorbeeld er zo uit:

import { useState } from 'react';

const BasicForm = () => {
  const [name, setName] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    alert(`Naam: ${name}`);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input 
        type="text"
        value={name}
        onChange={(e) => setName(e.target.value)}
        placeholder="Typ je naam"
      />
      <button type="submit">Verstuur</button>
    </form>
  );
};

export default BasicForm;

Belangrijk: Gebruik altijd e.preventDefault() bij onSubmit om te voorkomen dat de pagina refresht!

Controlled Component:

  • value={name} - React controleert de waarde
  • onChange - Update state bij elke wijziging
  • State is de "single source of truth"

Verschillende Input Types

Text Input

const [text, setText] = useState('');

<input 
  type="text"
  value={text}
  onChange={(e) => setText(e.target.value)}
/>

Email Input

const [email, setEmail] = useState('');

<input 
  type="email"
  value={email}
  onChange={(e) => setEmail(e.target.value)}
/>

Checkbox

const [agreed, setAgreed] = useState(false);

<input 
  type="checkbox"
  checked={agreed}
  onChange={(e) => setAgreed(e.target.checked)}
/>

Let op: Bij checkbox gebruik je checked in plaats van value en e.target.checked in plaats van e.target.value!

Select Dropdown

const [country, setCountry] = useState('');

<select value={country} onChange={(e) => setCountry(e.target.value)}>
  <option value="">Kies een land</option>
  <option value="nl">Nederland</option>
  <option value="be">België</option>
  <option value="de">Duitsland</option>
</select>

Anders dan in HTML! In gewone HTML zet je selected op een <option>. In React zet je value op de <select> zelf — de option met die waarde wordt automatisch geselecteerd.

Textarea

const [message, setMessage] = useState('');

<textarea 
  value={message}
  onChange={(e) => setMessage(e.target.value)}
  rows="5"
/>

Form met Object State

Voor forms met meerdere velden is het handig om een object te gebruiken:

import { useState } from 'react';

const UserForm = () => {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    age: ''
  });

  const handleChange = (e) => {
    setFormData({
      ...formData,
      [e.target.name]: e.target.value
    });
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log(formData);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input 
        type="text"
        name="name"
        value={formData.name}
        onChange={handleChange}
        placeholder="Naam"
      />
      
      <input 
        type="email"
        name="email"
        value={formData.email}
        onChange={handleChange}
        placeholder="Email"
      />
      
      <input 
        type="number"
        name="age"
        value={formData.age}
        onChange={handleChange}
        placeholder="Leeftijd"
      />
      
      <button type="submit">Verstuur</button>
    </form>
  );
};

Voordeel: Eén handleChange functie voor alle inputs! Gebruik name attribute om te weten welk veld verandert.

Form Validatie

Controleer of de input correct is voordat je het verstuurt:

import { useState } from 'react';

const LoginForm = () => {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [error, setError] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    setError(''); // Reset error

    // Validatie
    if (!email) {
      setError('Email is verplicht');
      return;
    }
    
    if (!password || password.length < 6) {
      setError('Wachtwoord moet minimaal 6 karakters zijn');
      return;
    }

    // Submit form
    console.log('Form is valid!', email, password);
  };

  return (
    <form onSubmit={handleSubmit}>
      {error && <p style={{ color: 'red' }}>{error}</p>}
      
      <input 
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        placeholder="Email"
      />
      
      <input 
        type="password"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
        placeholder="Wachtwoord"
      />
      
      <button type="submit">Login</button>
    </form>
  );
};

Praktische Voorbeelden

Contact Form

const ContactForm = () => {
  const [form, setForm] = useState({
    name: '',
    email: '',
    message: ''
  });

  const handleSubmit = (e) => {
    e.preventDefault();
    // Send to API
    console.log('Sending:', form);
    // Reset form
    setForm({ name: '', email: '', message: '' });
  };

  const handleChange = (e) => {
    setForm({
      ...form,
      [e.target.name]: e.target.value
    });
  };

  return (
    <form onSubmit={handleSubmit}>
      <input 
        name="name"
        value={form.name}
        onChange={handleChange}
        placeholder="Naam"
        required
      />
      
      <input 
        name="email"
        type="email"
        value={form.email}
        onChange={handleChange}
        placeholder="Email"
        required
      />
      
      <textarea 
        name="message"
        value={form.message}
        onChange={handleChange}
        placeholder="Bericht"
        required
      />
      
      <button type="submit">Verstuur</button>
    </form>
  );
};

Form met Select Dropdown

Een select werkt net als een input in een form-object: je geeft de <select> een name en value, en je hergebruikt dezelfde handleChange.

const OrderForm = () => {
  const [form, setForm] = useState({
    name: '',
    country: 'nl',
    shipping: ''
  });

  const handleChange = (e) => {
    setForm({
      ...form,
      [e.target.name]: e.target.value
    });
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log('Bestelling:', form);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        name="name"
        value={form.name}
        onChange={handleChange}
        placeholder="Naam"
      />

      <select
        name="country"
        value={form.country}
        onChange={handleChange}
      >
        <option value="nl">Nederland</option>
        <option value="be">België</option>
        <option value="de">Duitsland</option>
      </select>

      <select
        name="shipping"
        value={form.shipping}
        onChange={handleChange}
      >
        <option value="">Kies verzending...</option>
        <option value="standard">Standaard (3-5 dagen)</option>
        <option value="express">Express (1 dag)</option>
      </select>

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

Tips:

  • Wil je een standaardwaarde? Zet die in useState (bv. country: 'nl').
  • Wil je dat de gebruiker moet kiezen? Begin met een lege optie <option value="">Kies...</option> en valideer in handleSubmit.
  • Opties uit een array? Gebruik .map(): {`countries.map(c => <option key={c.code} value={c.code}>{c.name}</option>)`}

Registration Form met Checkbox

const RegisterForm = () => {
  const [form, setForm] = useState({
    email: '',
    password: '',
    agree: false
  });

  const handleSubmit = (e) => {
    e.preventDefault();
    if (!form.agree) {
      alert('Je moet akkoord gaan met de voorwaarden');
      return;
    }
    console.log('Registering:', form);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input 
        type="email"
        value={form.email}
        onChange={(e) => setForm({...form, email: e.target.value})}
      />
      
      <input 
        type="password"
        value={form.password}
        onChange={(e) => setForm({...form, password: e.target.value})}
      />
      
      <label>
        <input 
          type="checkbox"
          checked={form.agree}
          onChange={(e) => setForm({...form, agree: e.target.checked})}
        />
        Ik ga akkoord met de voorwaarden
      </label>
      
      <button type="submit">Registreer</button>
    </form>
  );
};