Hvordan kan setInterval brukes for å endre state i react?

Jeg har merket at jeg ikke er så flink til å ta pauser mens jeg arbeider. Tenkte å få til litt mer struktur med og kun jobbe i 30 minutters intervaller. Desverre finnes det ingen klokker som tilbyr den avanserte nedtellingsfunksjonaliteten jeg ønsker ( :wink: ), så tenkte derfor jeg skulle lage en liten app for å fikse problemet mitt.

Men så oppsto det et problem nesten med en gang, som jeg ikke helt klarer å forstå. Jeg skal kun lage en applikasjon som teller ned fra 30:00 til 00:00. Tenkte å gjøre det ved å sette opp en interval som decrementerte en timer hvert sekund. Jeg har skrevet følgende kode:

Resultatet er at decrementTimer kalles hvert sekund, men for den er timer-variabelen lik -1 på hvert kall. Kan noen foklare meg hva som skjer?

2 Likes

Oof… Set interval er tricky med hooks. Dan abramov skrev en lang blogpost om det: https://overreacted.io/making-setinterval-declarative-with-react-hooks/

1 Like

En enkel fiks er å bruke callback varianten av setTimer:
setTimer(timer => timer - 1)

2 Likes

Eller var jeg litt kjapp, var noe greier med setInterval ja :stuck_out_tongue: lese den posten til Abramov igjen

Edit: hmm den bloggen til mr Abramov handlet vel mer om å få setInterval til å være deklarativ, og passe på at den brukes riktig i en react sammenheng (?, jeg bare skummet over igjen nå).

Men, husk at med funksjons-komponenter i react så kjøres funksjonen ved hver re-render, i dette tilfelle betyr det at decrementTimer funksjonen din blir re-deklarert etter hver render, det er kun den gjeldende deklarasjonen av funksjonen som gjelder når startNewTimer kalles som blir kalt av setInterval. Dette betyr at funksjonen som setInterval kaller hvert sekund er den hvor decrementTimer funksjonen har fanget verdien -1 for timer (som var verdien som decrementTimer fanget i den gjeldende deklarasjonen av funksjonen).

Litt vanskelig forklart kanskje, si ifra om det ikke maker noe sense :stuck_out_tongue:

Løsningen min burde funke, men jeg anbefaler deg å studere løsningen til dan abramov også, som gjør at du unngår denne typen bugs :wink:

2 Likes

Han nevner det i artikkelen under “Second Attempt”:

The problem is that useEffect captures the count from the first render. It is equal to 0 . We never re-apply the effect so the closure in setInterval always references the count from the first render, and count + 1 is always 1 . Oops!

Samme problemet her, som du nevnte @Enochian

Og videre:

One way to fix it is to replace setCount(count + 1) with the “updater” form like setCount(c => c + 1) . It can always read fresh state for that variable. But this doesn’t help you read the fresh props, for example.

2 Likes

Ja se der ja, jeg skumma forbi alt det der jeg :upside_down_face:

Har skumma den noen ganger selv, men tror jeg må skumme den enda par ganger før det sitter skikkelig :stuck_out_tongue: Det er så sjelden man kommer borti de tilfellene der at det er lett å glemme

Jeg var litt usikker på om jeg skulle poste spørsmålet, men nå er jeg veldig glad for at jeg gjorde det. Her var det mye å lære. Skikkelig bra post det der!

Det gav veldig mening, tusen takk!

1 Like