1

Alright so I am building this CRUD app with a React driven U/I. I'm having an issue with my state updating. Below are the code snippets that are involved in the problem. I've tried figuring it out myself and think it's that my state is updating correctly but it gets sent to the server before the state can be updated and when my component remounts it gets the old state from the server and overwrites the new one. The server always gets a state that is n - 1 to the actual number of items. Also if you know any ways that i could improve, please let me know I feel like this is a lot of work to do just 3 tasks!

Thank you in advance.

My state

     this.state = {
            newItem:{},
            todos:[]
        }

The retrieval methods

    componentDidMount(){
        this.getTodos(this.props);
    }

    getTodos(props){
        axios.get(process.env.REACT_APP_SERVER+`/${props.match.params.id}/todos`)
        .then(
            (res)=>{
                this.setState({todos:[...res.data]});
            }
        )
    }

My creation and update methods

    handleOnChange(e){
        this.setState({newItem:{title:e.target.value, complete:false}});
    }

    addNewItem(){
        this.setState({todos:[...this.state.todos, this.state.newItem]});
        this.updateTodoList(this.props);
    }

    updateTodoList(props){
        axios.put(process.env.REACT_APP_SERVER+`/${props.match.params.id}/todo/add`, this.state.todos).then(res=>{
            console.log(res.data);
        });
    }

Update: Oh snap! That is what I figured, you've fixed my bug!

  • Does this answer your question? [When to use React setState callback](https://stackoverflow.com/questions/42038590/when-to-use-react-setstate-callback) – Agney Apr 05 '20 at 08:23
  • @DarkQuaesar - the setState does not execute in same method you call it "addNewItem", you need to sent new todos right there and let state update on its own – Kostia Mololkin Apr 05 '20 at 09:09

2 Answers2

0

The problem is you're calling updateTodoList before the state is already updated.

Do this:

addNewItem(){
        this.setState({todos:[...this.state.todos, this.state.newItem]}, () => {
              this.updateTodoList(this.props);
        });
    }

setState has a callback that is invoked after state is already updated so is the place you can be sure it is, and call next fn.

Adolfo Onrubia
  • 1,781
  • 13
  • 22
  • Great answer! I would advise to first create a const with the new todos, and then call setState and this.updateTodoList, without the callback. Then both calls would be parallel, instead of one after another. This would be a slightly more performant setup. – wintvelt Apr 05 '20 at 20:21
0

The state update is an asynchronous process.

The issue here is your update API call is happening before the state update.

To fix this issue use this syntax for state update.

addNewItem () {
  this.setState (
    {todos:[...this.state.todos, this.state.newItem]},
    () => {
    this.updateTodoList(this.props);
    }
  );           
}