-1

I'm trying to update the same state from an asynchronous callback launched in parallel. The problem is that each one of the asynchronous callback always has the init state and doesn't get the updated one. I've been a day trying different solutions but none worked. Is there a way to perform it?

Code example:

import React, { useState } from 'react';
import Button from '@material-ui/core/Button';
import http from '../../utils/clientHttp/clientHttp';


function Example() {
    const [calls, setCalls] = useState<string[]>([]);
    const [callsState, setCallsState] = useState<{[key:string]: string}>({ call1: 'init', call2: 'init', call3: 'init' });

    const onClick = () => {
        setCalls(['call1', 'call2', 'call3']);
        calls.forEach((call) => {
            http.post(call, '').then(() => {
                const copy = { ...callsState };
                copy[call] = 'done';
                setCallsState(copy);
            }).catch(() => {
                const copy = { ...callsState };
                copy[call] = 'error';
                setCallsState(copy);
            });
        });
    };

    return (
        <Button
            variant="contained"
            color="primary"
            onClick={onClick}
        >
            Try
        </Button>
    );
}

All of them go to error and the console log:

enter image description here

1 Answers1

0

You need to use callback approach to state mutation to avoid using stale object

const onClick = () => {
    setCalls(['call1', 'call2', 'call3']);
    calls.forEach((call) => {
        http.post(call, '').then(() => {
            setCallsState(state => ({ ...state, [call]: 'done' }));
        }).catch(() => {
            setCallsState(state => ({ ...state, [call]: 'error' }));
        });
    });
};
Yury Tarabanko
  • 44,270
  • 9
  • 84
  • 98