javascriptreactjscomponentsstatererender

How do I update State inside of a while loop in React


Say I have this code.

var s = [1,2,3,4,5,6,7,8,9,0];
const[arr,setArr]=useState(s);
while(arr.length != 0){
    setArr(arr.splice(0,1));
    console.log(arr); //This returns [2,3,4,5,6,7,8,9,0] and [3,4,5,6,7,8,9,0] and so on until []
}

I return {arr.length} at the end of the functionanl component. However, it first renders 10, and waits till the whole while loop is run and then renders 1. All the numbers inbettween are simply skipped.

I kind of understand why this happens, but is there anyway I can show all the lengths? I have a sleep function that takes milliseconds and halts the program for that time, if it is of any use in order to make sure the user can see the rendered lengths for a reasonable time.

Thanks in advance!


Solution

  • Assuming this is a functional component (I'm guessing you meant useState, not setState, in const[arr,setArr]=setState(s);), you need to let the component render each state before setting the next. Otherwise, all the state updates get batched together and the component only renders again when they're all done.

    For instance:

    function Example() {
        const [arr, setArr] = useState([1,2,3,4,5,6,7,8,9,0]);
        // Set up a timer on mount, remove it on dismount and when
        // we run out of values to show
        useEffect(() => {
            const handle = setInterval(() => {
                // Note useing the callback function, so `arr` isn't stale
                // in this callback
                setArr(a => {
                    if (a.length) {
                        // Update the array, dropping the first entry
                        return a.slice(1);
                    }
                    // No more entries, stop the timer
                    clearInterval(handle);
                    return a;
                });
            }, 500);
            return () => clearInterval(handle);
        }, []);
        return <div>{arr.join()}</div>;
    }