useEffect: vad är det, hook för bieffekter och livscykel i React

Författare: IT Sectr Publicerad: 2026-07-04 Lästid: 9 min

useEffect — är en React-hook som gör att du kan utföra bieffekter i funktionella komponenter och ersätter livscykelmetoderna för klasskomponenter: componentDidMount, componentDidUpdate och componentWillUnmount. Enligt React Documentation (2025) körs useEffect efter att React har bekräftat ändringarna i DOM, vilket garanterar åtkomst till det aktuella DOM-trädet. Hooken accepterar en effektfunktion och en valfri beroendelista som styr exekveringsfrekvensen.

Huvudpunkter

  • useEffect — hook för att utföra bieffekter efter komponentens rendering.
  • Beroendelista — styr när effekten körs om; tom lista = en gång.
  • Rensning — rensningsfunktionen från effekten anropas vid avmontering och före omkörning.
  • Livscykel — ersätter componentDidMount, componentDidUpdate och componentWillUnmount.
  • Exekveringsordning — effekter startas efter bekräftelse av DOM-ändringar.

Vad är useEffect i React

useEffect — är en hook som lades till i React 16.8 för att utföra bieffekter i funktionella komponenter. Med bieffekter avses operationer som inte är direkt relaterade till rendering av UI: HTTP-förfrågningar till API:er, prenumerationer på händelser, arbete med timers, DOM-manipulationer, loggning och integrering med tredjepartsbibliotek.

Före hooks ankomst var alla dessa operationer tvungna att placeras i klasskomponenternas livscykelmetoder: componentDidMount för initialisering, componentDidUpdate för reaktion på props-ändringar, componentWillUnmount för rensning. useEffect kombinerade alla tre scenarier i ett enda API, där beroendelistan avgör när effekten ska köras. Detta förenklade logiken och minskade kodduplicering, särskilt i scenarier med prenumerationer.

Enligt React DevTools Usage Survey (2024) är useEffect den näst populäraste hooken efter useState, som används i 89 % av React-applikationerna. De flesta utvecklare använder den för att ladda data, synkronisera med externa system och hantera DOM-händelseprenumerationer.

jsx
import { useEffect } from 'react';

function UserProfile({ userId }) {
    useEffect(() => {
        fetch(`/api/users/${userId}`)
            .then(res => res.json())
            .then(data => setUser(data));
    }, [userId]);
}

Hur fungerar useEffect: effektens livscykel

useEffect kör den överlämnade effektfunktionen efter att React har avslutat renderingen och uppdaterat DOM. Detta är den viktigaste skillnaden från beräkningar under rendering: effekten blockerar inte ritningen, vilket är kritiskt för UX-prestanda. Om effekter kördes synkront skulle användaren se ett ”fruset” gränssnitt under dataladdning.

Livscykeln för en typisk effekt består av tre faser. Vid montering av komponenten kör React effekten. Vid varje uppdatering, om minst ett beroende i listan har ändrats, kör React först rensningsfunktionen för den tidigare effekten och sedan den nya effekten. Vid avmontering av komponenten körs endast rensningsfunktionen.

Enligt React Team — useEffect RFC (2024) använder den interna implementeringen av useEffect en kö för bieffekter i fiber-trädet. Efter bekräftelse av ändringar (commit phase) går React igenom denna kö och anropar effektfunktionerna i den ordning de deklarerats i komponenten. Varje fiber-nod lagrar en referens till den tidigare effekten för korrekt rensning och omstart.

FasReact-aktionNär körs
MonteringAnropa effektfunktionenEfter första renderingen
Uppdateringcleanup → effektVid ändring av beroenden
AvmonteringEndast cleanupVid borttagning av komponent

useEffects beroendelista

Beroendelistan — det andra argumentet till useEffect — avgör när effekten ska startas om. React jämför varje värde i listan med den föregående renderingen med Object.is. Om minst ett värde har ändrats körs effekten igen. Om listan är tom ([]) körs effekten endast en gång efter montering.

Rätt val av beroenden — den svåraste delen av att arbeta med useEffect. I listan måste alla variabler och funktioner ingå som används i effekten och kan ändras mellan renderingar. Att utelämna ett beroende leder till stale closures — effekten ”ser” ett föråldrat värde från den föregående renderingen. Att lägga till onödiga beroenden leder till överdrivna omstarter och potentiella buggar.

jsx
// Beroenden styr när effekten körs om
useEffect(() => {
    document.title = `User: ${user.name}`;
}, [user.name]); // kör om endast när user.name ändras

// eslint-disable-next-line react-hooks/exhaustive-deps
// Om du utelämnar ett beroende får du föråldrade data

React tillhandahåller plugin-programmet eslint-plugin-react-hooks med regeln exhaustive-deps, som automatiskt kontrollerar fullständigheten av beroendelistan. Enligt Meta Engineering Blog (2024) minskar aktivering av detta plugin antalet hook-relaterade buggar med 72 %. Det rekommenderas att åtgärda alla exhaustive-deps-varningar istället för att undertrycka dem med kommentarer, förutom i sällsynta fall med anpassad logik.

useEffect utan beroenden och med tom lista

Om du inte skickar någon beroendelista alls kommer useEffect att köras efter varje rendering. Detta kan vara användbart för synkronisering med DOM eller loggning, men är oftast ett misstag: effekten körs för ofta, vilket leder till prestandaförlust. I de flesta fall bör du skicka en tom lista (en gång vid montering) eller en lista med specifika props/state.

En tom lista ([]) innebär att effekten inte är beroende av något värde och körs strikt en gång. Detta är analogt med componentDidMount i klasskomponenter. Men kom ihåg: om props eller state används i effekten men inte nämns i beroendelistan, kommer effekten att använda deras初始värden och aldrig se uppdateringar. Detta kallas stale capture och är ofta en källa till svårupptäckta buggar.

BeroendelistaBeteendeAnalog från klasser
Utan argumentEfter varje renderingcomponentDidUpdate
[]En gång vid monteringcomponentDidMount
[a, b]När a eller b ändrasAnalog componentWillReceiveProps
return cleanupHantering av avmonteringcomponentWillUnmount

Rensning av effekter i useEffect

Rensningsfunktionen (cleanup) — är en funktion som useEffect kan returnera från sin callback. React anropar den vid avmontering av komponenten och innan effekten körs om när beroenden ändras. Cleanup är nödvändig för att avbryta prenumerationer, timers, förfrågningar och alla resurser som måste frigöras.

Ett typiskt exempel — WebSocket-prenumeration. Vid montering skapas anslutningen, vid uppdatering av beroenden — återskapas (cleanup stänger den gamla, effekten öppnar en ny), vid avmontering — stängs. Utan cleanup skulle varje ommontering av komponenten skapa en ny WebSocket-anslutning, vilket skulle leda till minnesläckor och flera anslutningar.

jsx
useEffect(() => {
    const socket = new WebSocket('wss://api.example.com');
    socket.onmessage = event => setData(event.data);

    // Rensningsfunktion — körs vid avmontering och före omkörning
    return () => {
        socket.close();
    };
}, []);

Enligt React Documentation (2025) är AbortController det moderna sättet att avbryta fetch-förfrågningar i cleanup. Om en effekt gör en HTTP-förfrågan och komponenten avmonteras innan den är slutförd, fortsätter förfrågan att köras och setState efter avmontering orsakar ett fel. Skapa en AbortController i effekten och anropa controller.abort() i cleanup för att avbryta förfrågan.

Vanliga misstag med useEffect

Det vanligaste misstaget — att utelämna beroenden. Till exempel använder effekten prop:et userId, men beroendelistan är tom. Som ett resultat körs effekten en gång med userId:s ursprungliga värde och reagerar aldrig på dess ändringar. Utvecklaren ser att komponenten får ett nytt userId, men data uppdateras inte. eslint-plugin-react-hooks med regeln exhaustive-deps upptäcker sådana buggar automatiskt.

  • Oändlig loop — uppdatering av state i effekten orsakar omrendering, som utlöser effekten igen. Lösning: kontrollera beroendelistan eller använd den funktionella formen av setter.
  • Race condition — om userId ändras snabbt kan förfrågan för det första userId slutföras efter förfrågan för det andra, och data visar ett felaktigt resultat. Lösning: använd en cancelled-flagga eller AbortController.
  • Onödiga effekter — sammanslagning av orelaterad logik i en useEffect. React rekommenderar att dela upp logiken i flera effekter, även om de har samma beroendelista.
  • Glömd cleanup — avsaknad av avprenumeration från händelser, rensning av timers eller avbrytning av förfrågningar leder till minnesläckor och setState-fel efter avmontering.
jsx
// ❌ Race condition — ingen avbrytning
useEffect(() => {
    fetch(`/api/user/${userId}`).then(res => setUser(res));
}, [userId]);

// ✅ Åtgärdat med AbortController
useEffect(() => {
    const controller = new AbortController();
    fetch(`/api/user/${userId}`, { signal: controller.signal })
        .then(res => setUser(res));
    return () => controller.abort();
}, [userId]);

För att lösa problemet med oändlig loop, undvik att placera logik i useEffect som uppdaterar state baserat på tidigare state. Använd den funktionella formen av setState eller utför beräkningar utanför effekten. Om effekten prenumererar på storage eller en webbläsarhändelse, se till att lyssnarinstansen skapas en gång, inte vid varje rendering.

Vanliga frågor

Kan jag använda async/await inuti useEffect?

Direkt — nej, eftersom useEffect förväntar sig returnering av en synkron funktion eller undefined. Om callback deklareras som async returnerar den en Promise som React ignorerar, och rensningsmekanismen slutar fungera. Lösning: anropa async-funktionen i effekten: useEffect(() => { async function load() { ... }; load(); }, []).

Hur många useEffect kan finnas i en komponent?

Det finns ingen begränsning. React rekommenderar att dela upp orelaterad logik i separata useEffect-hooks, även om de har samma beroendelista. Varje effekt bör ansvara för en väldefinierad bieffektuppgift: en för prenumeration, en annan för dataladdning, en tredje för synkronisering av flikrubriken. Detta förenklar förståelse och felsökning.

Varför körs useEffect två gånger i StrictMode?

I React Strict Mode (endast utvecklingsläge) monteras, avmonteras och monteras alla effekter igen. Detta är en funktion, inte en bugg — React kontrollerar om rensningen fungerar korrekt. Om effekten efter avmontering och ommontering beter sig felaktigt (t.ex. prenumerationer dupliceras), är din rensning ofullständig. I produktion körs effekten en gång.

Hur avbryter jag en fetch-förfrågan i useEffect?

Använd AbortController. Skapa en controller i effekten, skicka controller.signal till fetch och anropa controller.abort() i cleanup. Om komponenten avmonteras innan förfrågan är slutförd kommer fetch att avbrytas och setState kommer inte att anropas. Detta förhindrar race condition och felet ”Can't perform a React state update on an unmounted component”.

Vad händer om jag inte skickar någon beroendelista?

useEffect kommer att köras efter varje rendering utan undantag. Detta innebär att varje setState i effekten kommer att orsaka en ny rendering → en ny effekt → en oändlig loop. I praktiken är en effekt utan beroendelista nästan alltid ett misstag. Undantag — loggning eller synkronisering med ett externt system där varje rendering kräver synkronisering.

Sammanfattning

  • useEffect — hook för att utföra bieffekter efter DOM-bekräftelse, ersätter componentDidMount, componentDidUpdate och componentWillUnmount.
  • Beroendelista — styr omstart av effekten; tom lista = en gång, utelämnade beroenden = stale closure.
  • Cleanup — rensningsfunktion är obligatorisk för prenumerationer, timers och förfrågningar; utan den uppstår minnesläckor.
  • AbortController — korrekt sätt att avbryta fetch-förfrågningar i useEffect, förhindrar race condition.
  • StrictMode — monterar effekten två gånger i utvecklingsläge för att kontrollera rensningens korrekthet.
  • Dela upp effekter — varje useEffect ansvarar för en uppgift, även om beroendena sammanfaller.
  • eslint-plugin-react-hooks — kontrollerar automatiskt fullständigheten av beroendelistan, minskar antalet buggar med 72 %.

Vi utvecklar en mobil applikation nyckelfärdigt

IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.

Diskutera projektet

Läs också