'setState doesn't work as expected. It takes the initial state each time time

So I have this code snippet, where I have to update the state and call the api each time the button gets click. The first time it works as expected but the next time it sets the endTime to initial time and sets the startTime with 2 hours prior to what was expected. My console log works perfectly but there is some issues while I am trying to setState. I have tried adding a callback function after each setState and also tried setting the state after the end of if-else but it doesn't show me the required result.

class ButtonComponent extends Component{
     constructor(props) {
            super(props);
            this.state = {
               timeData: {
                    endTime: moment(),
                    startTime: moment().subtract(2, 'h'),
                  
                },
                dropdownOption: '2HOURS'
    }
     this.callAPI= this.callAPI.bind(this);
    }

    componentDidMount() {
                if (this.state.dropdownOption=== '2HOURS') {
                   this.callAPI();
                }         
            }
        
    onClick(){
                let time = {...this.state.timeData};
                let option;
                option = this.state.dropdownOption;
                if(option === '10hours'){
                time['endTime'] =timeData['startTime'];
                console.log('endTime', timeData['endTime'])
                time['startTime'] = timeData['endTime'].subtract(10, 'h');
                console.log('startTime', time['startTime'])
                this.setState({timeData: time}, this.callAPI())
            }
        }
    
    }
}


Solution 1:[1]

I'm not sure to understand what you want to do but, you should take care of the fact that setState is asynchronous, so if you call callAPI the same moment you call setState it's normal that callAPIdoesn't get the updated state. (I think I understand that this is the way you are trying to use your callAPI).

Here is a suggestion of implementation, at least to get it clearer:

class ButtonComponent extends Component{
    constructor(props) {
        super(props);
        this.state = {
            timeData: {
                endTime: moment(),
                startTime: moment().subtract(2, 'h'),
            },
            dropdownOption: '2HOURS',
        };
        this.callAPI= this.callAPI.bind(this);
    }

    componentDidMount() {
        if (this.state.dropdownOption=== '2HOURS') {
            this.callAPI();
        }         
    } 
    callAPI() {
       console.log("updated state", this.state.timedata)
    }

    onClick() {
        const timeData = {...this.state.timeData};
        const option = this.state.dropdownOption;
        if(option === '10hours') {
            // I quite don't get the way you want to update your state so this might need to be adapted.
            timeData.endTime = timeData.startTime;
            timeData.startTime = moment();

            // this.callAPI willl be called as soon as the state update is resolved by setState so the new state will be available inside callAPI.
            this.setState({timeData}, this.callAPI);
        }
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1