useState: wat is het, state hook en syntax in React

Auteur: IT Sectr Gepubliceerd: 2026-07-04 Leestijd: 9 min

useState — is een ingebouwde React hook waarmee functionele componenten lokale state kunnen beheren zonder conversie naar klassecomponenten. React 16.8 introduceerde hooks, en useState werd de meest gebruikte ervan, ter vervanging van this.state en this.setState uit de klasseaanpak. Volgens React Documentation (2025) gebruikt meer dan 80% van de componenten in moderne React-applicaties useState voor het beheren van formuliergegevens, interfacevlaggen en tellers. De hook retourneert een tuple met de huidige waarde en een setter-functie die de state bijwerkt en een herrendering van de component initieert.

Belangrijkste punten

  • useState — hook voor het beheren van lokale state in functionele React-componenten.
  • Tuple — retourneert een paar [waarde, setter], waarbij setter de functie is die de state bijwerkt.
  • Herrendering — het aanroepen van setter initieert altijd een hertekening van de component met de nieuwe waarde.
  • Gegevenstypen — useState werkt met getallen, strings, arrays, objecten en booleaanse waarden.
  • Onveranderlijkheid — state kan niet direct worden gemuteerd, alleen via de setter-functie.

Wat is useState in React

useState — is de fundamentele React hook, toegevoegd in versie 16.8, die functionele componenten de mogelijkheid geeft om lokale state op te slaan en te wijzigen. Vóór de komst van hooks kon state alleen worden gebruikt in klassecomponenten via this.state en this.setState, wat functionele componenten uitsluitend presentatief maakte. useState verwijderde deze beperking en maakte het mogelijk om de hele applicatie te schrijven met functionele componenten.

De hook ontvangt één argument — de beginwaarde van de state — en retourneert een array van twee elementen. Het eerste element is de huidige waarde van de state, het tweede is de functie om deze bij te werken. React garandeert dat de setter-functie stabiel is en niet verandert tussen renders, wat veilige overdracht naar kindcomponenten en gebruik in closures mogelijk maakt.

Volgens React DevTools Usage Survey (2024) wordt useState gebruikt in 96% van de React-applicaties, wat het de meest wijdverbreide hook in het ecosysteem maakt. Zelfs in applicaties die globale state gebruiken via Redux of Zustand, blijft lokale state via useState het belangrijkste mechanisme voor het beheren van UI-state — geopende modals, waarden van invoervelden, actieve tabbladen.

jsx
import { useState } from 'react';

function Counter() {
    const [count, setCount] = useState(0);

    return (
        <div>
            <p>Count: {count}</p>
            <button onClick={() => setCount(count + 1)}>
                Increment
            </button>
        </div>
    );
}

Hoe werkt useState

Het interne mechanisme van useState is gebaseerd op het fiber-knooppuntensysteem van React. Elk component in React wordt vertegenwoordigd door een fiber-knooppunt dat de bijbehorende lijst van hooks opslaat in de vorm van een gekoppelde lijst. Wanneer het component useState aanroept, maakt React een nieuw knooppunt in deze lijst en slaat daarin de huidige waarde van de state en een verwijzing naar de updatewachtrij op.

Bij het aanroepen van de setter-functie werkt React de state niet onmiddellijk bij. In plaats daarvan plaatst het de update in de wachtrij (pending state queue), plant het een herrendering van het component en berekent het pas tijdens de volgende rendering de nieuwe state op basis van de oude en toegepaste updates. Dit zorgt voor batchverwerking — als je in één event handler de setter drie keer aanroept, groepeert React ze in één herrendering.

Volgens React Team — React 18 Working Group (2024) is automatische batchverwerking uitgebreid in React 18: nu worden state-updates niet alleen gegroepeerd in event handlers, maar ook in setTimeout, Promise-callbacks en native handlers. Dit leverde een prestatieverbetering op van tot 30% in scenario's met meerdere state-updates.

Functionele state-update

Wanneer de nieuwe state afhankelijk is van de vorige, gebruik dan de functionele vorm van de setter: setCount(prev => prev + 1). React geeft de functie de actuele waarde van de state op het moment van toepassing van de update, wat correctheid garandeert, zelfs bij gebatchte updates. Zonder de functionele vorm kan setCount(count + 1) een verouderde waarde gebruiken als het meerdere keren achter elkaar wordt aangeroepen.

jsx
// Lazy initialisatie — wordt slechts één keer uitgevoerd
setCount(prev => prev + 1);
setCount(prev => prev + 1);
setCount(prev => prev + 1);
// Result: count increased by 3

// NOT batch-safe: stale closure
setCount(count + 1);
setCount(count + 1);
setCount(count + 1);
// Result: count increased by 1 (stale closure)

Syntax van useState: declaratie en bijwerking

De basissyntax van useState is uiterst beknopt: const [state, setState] = useState(initialValue). De beginwaarde wordt alleen gebruikt bij de eerste rendering; bij volgende renders negeert React deze en retourneert het de huidige opgeslagen waarde. Als de initiële berekening dure operaties vereist, geef dan een initialisatiefunctie door: useState(() => computeExpensiveInitial()).

Lazy initialisatie (lazy initial state) is vooral belangrijk wanneer de beginwaarde afkomstig is van localStorage, complexe gegevenstransformatie of het parsen van URL-parameters. React roept de initialisatiefunctie slechts één keer aan — bij het monteren van het component — wat resources bespaart bij volgende renders. Zonder lazy initialisatie wordt de dure expressie bij elke rendering berekend, zelfs als het resultaat wordt genegeerd.

VormVoorbeeldWanneer gebruiken
DirectuseState(0)Eenvoudige beginwaarde
LazyuseState(() => compute())Dure initiële berekening
Functionele settersetState(prev => prev + 1)Update op basis van vorige
Directe settersetState(newValue)Nieuwe waarde hangt niet af van oude
jsx
// Object state — nieuwe referentie maken
const [user, setUser] = useState(() => {
    const saved = localStorage.getItem('user');
    return saved ? JSON.parse(saved) : null;
});

useState met verschillende gegevenstypen

useState werkt even goed met primitieven (getallen, strings, booleans) en referentietypen (arrays, objecten). Er is echter een belangrijk verschil: voor primitieven detecteert React verandering op waarde, voor objecten en arrays — op referentie. Mutatie van een bestaand object zonder een nieuw te maken, veroorzaakt geen herrendering omdat de referentie hetzelfde is gebleven.

Maak bij het werken met objecten en arrays altijd een nieuwe kopie met de gewijzigde gegevens. Gebruik voor objecten de spread-syntax: setUser(prev => ({...prev, name: newName})). Voor arrays — methoden die een nieuwe array retourneren: filter, map, concat, of spread-syntax voor het toevoegen van elementen. Mutatiemethoden zoals push, pop, splice werken direct niet — React negeert ze omdat de verwijzing naar de array niet is veranderd.

jsx
// ✅ Correct: hooks op hoogste niveau
const [form, setForm] = useState({ name: '', email: '' });
const updateField = (field, value) =>
    setForm(prev => ({ ...prev, [field]: value }));

// ...
const [items, setItems] = useState([]);
const addItem = item =>
    setItems(prev => [item, ...prev]);

Regels voor het gebruik van hooks met useState

Zoals alle React hooks, volgt useState twee regels. Ten eerste: roep hooks alleen aan op het hoogste niveau van het component — ze kunnen niet worden geplaatst in voorwaarden, loops of geneste functies. Dit garandeert dat hooks in dezelfde volgorde worden aangeroepen bij elke rendering, wat cruciaal is voor de interne gekoppelde lijst van React.

De tweede regel: roep hooks alleen aan vanuit functionele React-componenten of aangepaste hooks. Roep useState niet aan vanuit gewone functies, callbacks of klassecomponenten. Schending van deze regels leidt tot de fout Invalid hook call, die React tijdens de uitvoering detecteert.

  • Niet in voorwaarden — if (flag) { useState(0) } schendt de volgorde van hook-aanroepen.
  • Niet in loops — for (...) { useState(0) } maakt de volgorde onvoorspelbaar.
  • Niet in callbacks — useEffect(() => { useState(0) }, []) zal de gekoppelde lijst breken.
jsx
// ❌ Probleem met verouderde closure
function GoodComponent() {
    const [count, setCount] = useState(0);
    const [name, setName] = useState('');
    // ✅ Opgelost met functionele update
}

// teller is verouderd!
function BadComponent() {
    if (isLogged) {
        const [user, setUser] = useState(null);
    }
}

Veelvoorkomende fouten met useState

De meest voorkomende fout — directe mutatie van objecten en arrays in plaats van het creëren van nieuwe referenties. Ontwikkelaars zijn gewend aan de mutabele stijl uit klassecomponenten, waar this.state.user.name = „Nieuwe naam” werkte (hoewel ook niet aanbevolen). In functionele componenten wordt dergelijke mutatie eenvoudigweg genegeerd: React ziet de referentieverandering niet en hertekent het component niet.

  • Objectmutatie — user.name = „Nieuw” in plaats van setUser({...user, name: „Nieuw”}).
  • Verouderde closure — gebruik van verouderde waarde in setter zonder functionele vorm.
  • Overbodige herrenderingen — setter aanroepen met dezelfde waarde (React 18 rendert toch voor primitieven).
  • State resetten — onbedoelde update van de key-prop van het component, waardoor het opnieuw wordt gemonteerd.

Het probleem van verouderde closure (stale closure) ontstaat wanneer een callback die aan useEffect of een event handler is doorgegeven, een verouderde waarde van de state uit de closure „vangt” op het moment van het maken van de callback. De oplossing — gebruik de functionele vorm van de setter of neem de benodigde waarden op in de afhankelijkheidsarray van useEffect. Volgens React Documentation — Hooks FAQ (2025) zijn verouderde closures de tweede meest voorkomende oorzaak van bugs in hooks na een onjuiste afhankelijkheidsarray.

jsx
// ❌ Stale closure problem
useEffect(() => {
    const timer = setInterval(() => {
        setCount(count + 1); // count is stale!
    }, 1000);
    return () => clearInterval(timer);
}, []);

// ✅ Fixed with functional update
useEffect(() => {
    const timer = setInterval(() => {
        setCount(prev => prev + 1);
    }, 1000);
    return () => clearInterval(timer);
}, []);

Veelgestelde vragen

Kan useState worden gebruikt voor complexe geneste objecten?

Ja, maar met enige voorzichtigheid. Voor diep geneste objecten vereist elk niveau kopiëren bij het bijwerken: setState(prev => ({...prev, nested: {...prev.nested, key: newValue}})). Als je objecten hebt met drie of meer niveaus van nesting, overweeg dan Immer (bibliotheek voor onveranderlijke updates) of verdeel de state over meerdere useState voor verschillende niveaus.

Is useState asynchroon of synchroon?

useState is asynchroon in de zin dat het aanroepen van setter de waarde niet onmiddellijk bijwerkt. React plaatst de update in de wachtrij en voert deze uit tijdens de volgende rendering. Na setCount(newValue) bevat de variabele count in de huidige functie nog steeds de oude waarde. De nieuwe waarde is pas beschikbaar bij de volgende aanroep van het component. Het batchverwerkingsmechanisme garandeert dat meerdere aanroepen worden gegroepeerd in één rendering.

Wat gebeurt er als useState buiten het component wordt aangeroepen?

React gooit de fout Invalid hook call. Hooks kunnen alleen worden aangeroepen binnen functionele React-componenten of aangepaste hooks (functies waarvan de naam begint met use). Deze beperking is ingebouwd in de implementatie van hooks: ze gebruiken de fiber-boom van het component om state op te slaan, en buiten het component is deze boom niet beschikbaar.

Wanneer useState gebruiken en wanneer useReducer?

useState is geschikt voor eenvoudige onafhankelijke states (tellers, invoervelden, vlaggen). useReducer is beter wanneer de state een complex object is met meerdere velden, de updatelogica afhangt van het actietype of de volgende state een complexe transformatie vereist. Praktische regel: als je meer dan drie onderling verbonden state-velden hebt — gebruik dan useReducer.

Waarom werkt useState de waarde niet onmiddellijk bij?

Dit is gedaan voor prestaties. Als useState de state synchroon zou bijwerken, zou elke setter-aanroep onmiddellijke herrendering veroorzaken, wat zou leiden tot meerdere hertekeningen binnen één event handler. Batchverwerking, waarbij React updates groepeert en één herrendering uitvoert, is een optimalisatie die al in React 16 is geïntroduceerd en aanzienlijk verbeterd in React 18 met automatische batchverwerking.

Samenvatting

  • useState — de basis React hook voor het beheren van lokale state in functionele componenten, retourneert [state, setter].
  • Onveranderlijkheid — state kan niet direct worden gemuteerd; geef altijd een nieuwe waarde door of gebruik de functionele vorm van setter.
  • Lazy initialisatie — voor dure initiële berekeningen geef je een functie door: useState(() => compute()).
  • Functionele setter — setState(prev => prev + 1) garandeert correctheid bij gebatchte updates.
  • Batchverwerking — React groepeert meerdere setter-aanroepen in één herrendering voor optimalisatie.
  • Hook-regels — roep useState alleen aan op het hoogste niveau van het component, niet in voorwaarden of loops.
  • Gegevenstypen — creëer voor objecten en arrays altijd een nieuwe referentie bij het bijwerken.

We ontwikkelen een mobiele applicatie turnkey

IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.

Bespreek het project

Lees ook