React Hooks — wat zijn het, basis hooks en gebruiksregels

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

React Hooks — zijn functies waarmee je state, effecten, context en andere React-mogelijkheden kunt gebruiken in functionele componenten, zonder klassen te schrijven. Geïntroduceerd in React 16.8, hebben hooks de ontwikkelingsaanpak radicaal veranderd door complexe patronen zoals HOC en render props te vervangen. Volgens React, 2024 zijn er 15 ingebouwde hooks die alle scenario’s voor componentbeheer dekken.

Belangrijkste

  • Hooks — functies om React-mogelijkheden te koppelen aan functionele componenten zonder extends Component.
  • useState — basis hook voor statebeheer, retourneert waarde en setter.
  • useEffect — voor neveneffecten: API-verzoeken, abonnementen, timers, DOM-manipulaties.
  • useContext — voor toegang tot React-context zonder Consumer-omhulsels en static contextType.
  • Regels voor hooks — alleen op het hoogste niveau aanroepen en alleen binnen functionele componenten of aangepaste hooks.

Wat zijn React Hooks?

React Hooks — een set ingebouwde functies in React waarmee je ‘verbinding kunt maken’ met de interne mechanismen van het framework zonder klassen te maken. Vóór React 16.8 konden functionele componenten alleen props ontvangen en JSX retourneren — elke complexe logica vereiste een klassecomponent.

Het probleem van klassecomponenten — scheiding van gerelateerde logica. Code die bij één entiteit hoorde (bijvoorbeeld een WebSocket-abonnement) werd gedwongen verdeeld tussen componentDidMount, componentDidUpdate en componentWillUnmount. Hooks lossen dit op: alle logica wordt gegroepeerd in één useEffect.

Het tweede probleem — hergebruik van logica. Voor hergebruik van statelogica tussen klassecomponenten moesten HOC (componenten van hogere orde) of render props worden toegepast — beide patronen creëerden extra nesting in de componentenboom. Aangepaste hooks lossen dit probleem op zonder nesting.

useState — statebeheer

useState — de meest basale hook. Het accepteert een beginwaarde en retourneert een tuple: de huidige waarde en een functie om deze bij te werken. In tegenstelling tot this.setState in klassen, voegt useState objecten niet samen — de nieuwe state vervangt volledig de vorige voor een specifieke aanroep van useState.

js
import React, { useState } from 'react';

function Form() {
  const [text, setText] = useState('');
  const [submitting, setSubmitting] = useState(false);

  async function handleSubmit() {
    setSubmitting(true);
    await fetch('/api/submit', {
      method: 'POST',
      body: JSON.stringify({ text })
    });
    setSubmitting(false);
  }

  return (
    <div>
      <input
        value={text}
        onChange={e => setText(e.target.value)}
      />
      <button onClick={handleSubmit}
        disabled={submitting}>
        {submitting ? 'Saving...' : 'Submit'}
      </button>
    </div>
  );
}

Functionele vorm van setState

De setter van useState kan een functie accepteren die de vorige waarde ontvangt en een nieuwe retourneert. Functionele vorm is verplicht wanneer de nieuwe state wordt berekend uit de vorige en gebatchte aanroepen van setState mogelijk zijn — elke aanroep krijgt de actuele vorige waarde.

useEffect — neveneffecten en levenscyclus

useEffect — hook voor het uitvoeren van neveneffecten in functionele componenten. Het accepteert twee argumenten: een effectfunctie en een afhankelijkhedenarray. React voert het effect uit na elke render, maar bij het opgeven van afhankelijkheden — alleen wanneer een van hen is veranderd.

Een lege afhankelijkhedenarray [] betekent dat het effect eenmaal wordt uitgevoerd na de eerste render (analoog aan componentDidMount). Het retourneren van een functie uit het effect is de cleanup, die wordt uitgevoerd bij het ontmantelen (analoog aan componentWillUnmount) en voordat het effect opnieuw wordt uitgevoerd.

js
import React, { useState, useEffect } from 'react';

function ChatRoom({ roomId }) {
  const [messages, setMessages] = useState([]);

  useEffect(() => {
    const socket = new WebSocket(`wss://chat/${roomId}`);

    socket.onmessage = (event) => {
      setMessages(prev => [...prev, JSON.parse(event.data)]);
    };

    // Cleanup - socket sluiten
    return () => socket.close();
  }, [roomId]);

  return <ul>
    {messages.map((msg, i) =>
      <li key={i}>{msg.text}</li>
    )}
  </ul>;
}

De afhankelijkheden van useEffect — zijn de enige verbinding tussen het effect en de buitenwereld. Als in het effect een variabele uit props of state wordt gebruikt, moet deze in de afhankelijkhedenarray staan. Het negeren van deze regel is de bron van bugs met verouderde gegevens (stale closure).

useContext — toegang tot context

useContext — hook voor het lezen van de contextwaarde. Het accepteert het contextobject dat is gemaakt met React.createContext en retourneert de huidige waarde. Als de context verandert, wordt de component automatisch opnieuw gerenderd met de nieuwe waarde.

Vóór de komst van useContext vereiste toegang tot context in functionele componenten een omhulling in Context.Consumer, wat nesting creëerde. useContext elimineert Consumer volledig — het is voldoende om de hook aan te roepen op elke plek in de functionele component.

js
import React, { createContext, useContext } from 'react';

const ThemeContext = createContext('licht');

function ThemedButton() {
  const theme = useContext(ThemeContext);

  return <button
    className={`btn btn-${theme}`}
  >
    {theme === 'dark' ? 'moon' : '☀️'}
  </button>;
}

useContext is geen vervanging voor Redux of globale state. React raadt aan context te gebruiken voor zelden veranderende waarden — thema, taal, autorisatie. Voor veelvuldig bijgewerkte gegevens zal elke re-render alle consumenten van de context opnieuw berekenen, wat de prestaties kan verminderen.

useReducer — complexe statelogica

useReducer — alternatief voor useState voor states met complexe updatelogica. Het accepteert een reducer-functie en een begintoestand, retourneert de huidige state en een dispatch-functie. De reducer ontvangt de huidige state en actie, retourneert een nieuwe state — een pure functie zonder neveneffecten.

useReducer is vooral nuttig wanneer meerdere acties (set, reset, increment, addItem) één state beheren. In plaats van meerdere useState met verschillende setters — één reducer met duidelijke actietypen. Dit maakt de logica voorspelbaar en gemakkelijk te testen.

js
import React, { useReducer } from 'react';

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { ...state, count: state.count + 1 };
    case 'setStep':
      return { ...state, step: action.step };
    case 'reset':
      return { count: 0, step: 1 };
    default:
      throw new Error('Unknown action: ' + action.type);
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, {
    count: 0,
    step: 1
  });

  return (
    <>
      <p>Count: {state.count}</p>
      <button
        onClick={() => dispatch({ type: 'increment' })}>+</button>
      <button
        onClick={() => dispatch({ type: 'reset' })}>Reset</button>
    </>
  );
}

useRef, useMemo, useCallback — optimalisatie

useRef creëert een veranderlijk object dat behouden blijft tussen renders. Het wijzigen van current veroorzaakt geen re-render. Hoofdtoepassing — toegang tot DOM-elementen en opslag van muteerbare waarden (timers, vorige waarden, bibliotheekinstanties).

useMemo memoiseert het resultaat van een functie. Het herberekent de waarde alleen wanneer een van de afhankelijkheden verandert. Gebruik voor dure berekeningen — filteren van grote arrays, sorteren, gegevens formatteren. useCallback — een speciaal geval van useMemo voor het memoizeren van functies.

js
import React, { useRef, useMemo, useCallback } from 'react';

function SearchPage({ items, query, onItemSelect }) {
  const inputRef = useRef(null);

  // Autofocus bij montage
  useEffect(() => {
    inputRef.current?.focus();
  }, []);

  // Gefilterd resultaat memoizeren
  const filtered = useMemo(() => {
    return items.filter(item =>
      item.name.toLowerCase()
        .includes(query.toLowerCase())
    );
  }, [items, query]);

  // Callback memoizeren
  const handleSelect = useCallback((id) => {
    onItemSelect(id);
  }, [onItemSelect]);

  return (
    <div>
      <input ref={inputRef}
        value={query}
        onChange={e => setQuery(e.target.value)}
      />
      <ul>
        {filtered.map(item =>
          <li key={item.id}>
            <button
              onClick={() => handleSelect(item.id)}>
              {item.name}
            </button>
          </li>
        )}
      </ul>
    </div>
  );
}

Belangrijke regel: useRef, useMemo en useCallback — optimalisatiegereedschappen, geen verplichte constructies. Wikkel niet alles in useMemo — meet eerst de prestaties. Voortijdige optimalisatie maakt code complexer. React rendert componenten snel; useMemo is alleen nodig wanneer berekeningen echt duur zijn (O(n²) en hoger).

Regels voor hooks en veelgemaakte fouten

React heeft twee strikte regels voor hooks geïntroduceerd. Eerste: roep hooks alleen aan op het hoogste niveau — niet binnen voorwaarden, lussen of geneste functies. Tweede: roep hooks alleen aan vanuit React functionele componenten of aangepaste hooks. De ESLint-plugin eslint-plugin-react-hooks controleert automatisch beide regels.

De meest voorkomende fout — schending van de aanroepvolgorde van hooks. React vertrouwt op de volgorde van hook-aanroepen tussen renders. Als een hook zich binnen een voorwaarde bevindt en niet is aangeroepen in een van de renders, verschuiven alle volgende hooks, wat bugs veroorzaakt.

FoutWat gebeurt erOplossing
Hook in voorwaardeVolgorde van hooks raakt verstoordVerplaats de voorwaardelogica naar binnen de hook
Stale closureEffect gebruikt oude waardeVoeg alle afhankelijkheden toe aan de array
Oneindige lususeEffect zonder afhankelijkheden wijzigt stateSpecificeer afhankelijkheden of gebruik useReducer
Ref wijzigen in renderNeveneffect in functielichaamVerplaats mutaties naar useEffect

De tweede veelgemaakte fout — stale closure in useEffect. Als in het effect een variabele wordt gebruikt die niet in de afhankelijkheden is gespecificeerd, ‘vangt’ het effect de waarde op het moment van het maken van de sluiting. Oplossing — neem altijd alle gebruikte variabelen op in de afhankelijkhedenarray. Als er te veel afhankelijkheden zijn, splits het effect dan in meerdere delen.

Veelgestelde vragen

Waarom kunnen hooks niet worden aangeroepen in voorwaarden?

React vertrouwt op de volgorde van hook-aanroepen tussen renders. Als een hook is aangeroepen in een voorwaarde en niet heeft gewerkt in een van de renders, ‘verschuiven’ alle volgende hooks — hun state raakt vermengd. De ESLint-regel hooks/exhaustive-deps waarschuwt hiervoor.

Wat is het verschil tussen useEffect en useLayoutEffect?

useLayoutEffect is synchroon en wordt uitgevoerd voordat de browser wijzigingen tekent. useEffect is asynchroon — na het tekenen. Gebruik useLayoutEffect alleen wanneer je DOM moet meten of wijzigen voordat de gebruiker wijzigingen ziet (popover-positie, scroll-herstel).

Hoe annuleer je een fetch-verzoek bij ontmanteling?

Gebruik AbortController binnen useEffect. Maak een controller, geef signal door aan fetch en roep in de cleanup-functie controller.abort() aan. Voor oude browsers volstaat een cancelled-vlag: return () => { cancelled = true; } met controle vóór setState.

Wat is een aangepaste hook en wanneer maak je deze?

Een aangepaste hook — een JavaScript-functie met het voorvoegsel use die ingebouwde hooks gebruikt. Maak deze aan wanneer dezelfde logica met hooks wordt herhaald in twee of meer componenten. Voorbeelden: useDebounce, useLocalStorage, useMediaQuery. Aangepaste hooks vervangen HOC en render props.

Waarom wordt useEffect twee keer uitgevoerd in Strict Mode?

In Strict Mode monteert en ontmantelt React de component opzettelijk twee keer in de ontwikkelmodus om fouten met niet-opgeruimde effecten te vinden. Als de cleanup correct is geschreven, veroorzaakt de dubbele aanroep geen problemen. In de productiemodus gebeurt dit niet.

Samenvatting

  • React Hooks — functies voor het gebruik van state, effecten en context in functionele componenten, die klassen hebben vervangen.
  • useState — basis hook voor lokale state met functionele setter voor veilige updates.
  • useEffect — universele hook voor neveneffecten met afhankelijkhedenarray en cleanup-functie.
  • useContext — directe toegang tot React-context zonder Consumer-omhulsels en extra nesting.
  • useReducer — voor complexe statelogica met actietypen, alternatief voor Redux binnen één component.
  • useRef, useMemo, useCallback — optimalisatiegereedschappen: DOM-referenties, memoizatie van waarden en callbacks.
  • Hoogste-niveau-regel — strikte beperking voor het aanroepen van hooks buiten voorwaarden, lussen en geneste functies.

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