Waarom heb je useEffect nodig?
Stel je wilt iets doen zodra je component wordt geladen. Je zou denken: "Ik schrijf gewoon code in mijn component!"
Dit gaat fout (infinite loop!):
const Counter = () => {
const [count, setCount] = useState(0);
// Dit zorgt voor een infinite loop!
setCount(count + 1);
return <div>Count: {count}</div>;
};
Probleem: Elke keer dat je setCount aanroept, rendert het component opnieuw. Bij elke render wordt setCount weer aangeroepen → infinite loop!
Wat is useEffect?
useEffect is een React Hook die ervoor zorgt dat code wordt uitgevoerd op het juiste moment - niet bij elke render.
Wanneer gebruik je useEffect?
- Data ophalen van een API zodra component laadt
- De pagina titel veranderen
- Een timer starten
- Iets in de console loggen bij het laden
useEffect importeren
import { useState, useEffect } from "react";
Basis Syntax
useEffect(() => {
// Code die je wilt uitvoeren
console.log('Component is geladen!');
}, []); // ← Dependency array
useEffect heeft 2 dingen:
- Een functie - de code die je wilt uitvoeren
- Een dependency array - wanneer de code moet worden uitgevoerd
Dependency Array
De dependency array [] bepaalt wanneer useEffect wordt uitgevoerd:
1. Lege Array [] - Eén keer bij laden
useEffect(() => {
console.log('Component geladen!');
}, []); // Voer 1x uit bij mount
Gebruik dit voor: Data fetchen, timers starten, document title aanpassen
2. Met Dependencies - Bij verandering
const [count, setCount] = useState(0);
useEffect(() => {
console.log('Count veranderde naar:', count);
}, [count]); // Voer uit elke keer als count verandert
3. Geen Array - Bij elke render
useEffect(() => {
console.log('Component renderde opnieuw');
}); // Voer uit bij elke render (meestal niet nodig!)
Let op: Zonder dependency array wordt useEffect bij elke render uitgevoerd. Dit wil je bijna nooit!
Praktische Voorbeelden
Document Title Aanpassen
import { useState, useEffect } from 'react';
const Counter = () => {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `Count: ${count}`;
}, [count]); // Update title als count verandert
return (
<div>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
);
};
Console Log bij Laden
useEffect(() => {
console.log('Component is gemount!');
}, []); // Voer 1x uit bij laden
Data Fetchen (basis)
import { useState, useEffect } from 'react';
const Users = () => {
const [users, setUsers] = useState([]);
useEffect(() => {
// Fetch data bij laden
fetch('https://api.example.com/users')
.then(res => res.json())
.then(data => setUsers(data));
}, []); // Lege array = 1x uitvoeren
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
};
Cleanup Function
Soms moet je opruimen (cleanup) als component unmount. Bijvoorbeeld bij timers of event listeners:
Timer Voorbeeld
import { useState, useEffect } from 'react';
const Timer = () => {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
// Start timer
const interval = setInterval(() => {
setSeconds(s => s + 1);
}, 1000);
// Cleanup: stop timer bij unmount
return () => {
clearInterval(interval);
};
}, []); // Lege array = 1x uitvoeren
return <div>Seconds: {seconds}</div>;
};
Cleanup function:
De functie die je return in useEffect wordt uitgevoerd als het component unmount. Gebruik dit om timers te stoppen, event listeners te verwijderen, etc.
Belangrijke Regels
- Altijd dependency array gebruiken - Anders elke render!
- Lege array [] voor "run once" - Bij component mount
- Dependencies toevoegen - Als je state/props gebruikt in useEffect
- Cleanup bij timers/listeners - Return functie voor cleanup
Veelgemaakte Fouten
Fout - Geen dependency array:
useEffect(() => {
setCount(count + 1); // Infinite loop!
}); // Geen array = elke render!
Goed - Met lege array:
useEffect(() => {
// Voer 1x uit
}, []); // Lege array = mount only
Fout - Missing dependency:
useEffect(() => {
console.log(count);
}, []); // count ontbreekt in array!
Goed - Dependency toegevoegd:
useEffect(() => {
console.log(count);
}, [count]); // count is toegevoegd
Fout - Timer niet opruimen:
useEffect(() => {
setInterval(() => {
console.log('tick');
}, 1000);
// Geen cleanup = memory leak!
}, []);
Goed - Met cleanup:
useEffect(() => {
const id = setInterval(() => {
console.log('tick');
}, 1000);
return () => clearInterval(id); // Cleanup!
}, []);