reactjsasynchronousrecursioncountersetstate

Not possible to increment the counter using set state in a simple recursive function in React


I understand that setState is asynchronous, but does it explicitly wait for all other code to be executed before it completes (even setTimeout with delay)?

I've been trying to increment a counter using a simple recursive function in React, but setState never executes. I added a setTimeout with a one-second delay, just to give setState enough time to execute, but it just keeps waiting infinitely and never executes.

Is replacing useState with useRef the best solution, or are there more elegant solutions?

import { useState } from 'react';

const TestComponent = () => {

const [counter, setCounter] = useState(1);

const setStateTest = () => {        
    setCounter(prev => prev + 1); // this line of code never executes
    setTimeout(() => {
        if (counter < 10) {
            setStateTest(); // this recursion happens infinitely because counter is never incremented
            console.log(counter); // the logged value is always 1, no incrementing
        }
    }, 1000)
}

return <button onClick={setStateTest}>Set State Test</button>

}

Solution

  • States in React are asynchronous and the value will only update after the function has finished running. Since your function never stops running (as it loops the setTimeout), the asynchronous call never gets a chance to finish and update the state value, thus it remains at 1. For this reason, state is not the best way to do what you are currently trying to do. Define counter using let outside of the scope of TestComponent instead.