Osiris
Osiris

Reputation: 107

Clearing inputs in React

I have a component in which I create a new post. I have a state used to configure and create a form. The main object in the state is called formControls and inside each element looks something like this:

  title: {
    elementType: "input",
    elementConfig: {
      type: "text",
      placeholder: "Title"
    },
    value: "",
    validation: {
      required: true
    },
    valid: false,
    isTouched: false
  }

Then I have a submit handler in which I create a new post and I try to clear the inputs. I m using 2 way binding so I try to clear by looping through state, make copies and update the values for each elements in the formControls : title, author and content like this:

for (let key in this.state.formControls) {
      const updatedState = { ...this.state.formControls }; 
      const updatedInput = { ...this.state.formControls[key] };
      updatedInput.value = "";
      updatedState[key] = updatedInput;

      console.log(updatedState);
      this.setState({
          formControls: updatedState
      });
    }

The things is that it only clears the last element in the form (textarea). I console logged updatedState and in each iteration it clears the current input but in the next iteration the previous cleared input has again the value before clearing so only the last element is cleared in the end. If i move const updatedState = { ...this.state.formControls }; outside the for loop is behaves as it should. Does this happen because of async operation of setState() and it doesn t give me the right previous state when I try to update in each iteration?

I was hoping that maybe someone could help me understand why is like this. I would post more code but is quite long.

Upvotes: 1

Views: 46

Answers (1)

Bryce
Bryce

Reputation: 6610

The data available to you in the closure is stale after the first call to setState. All iterations in the for .. in block will be run with the "old" data, so your last iteration is the one which is actually setting the fields to the values as they were when the for .. in loop began.

Try calling setState only once and put all your required changes into that.

const updatedFormControls = { ...this.state.formControls };

for (let key in this.state.formControls) {
  const updatedInput = { ...updatedFormControls[key] };
  updatedInput.value = "";
  updatedFormControls[key] = updatedInput;
}

console.log(updatedFormControls);

this.setState({
    formControls: updatedFormControls
});

Another way to do the same thing might look like this:

this.setState(state => ({
   ...state,
   formControls: Object.keys(state.formControls).reduce(
     (acc, key) => ({ 
        ...acc,
        [key]: { ...state.formControls[key], value: '' }
     }),
     {}
   )
});

Upvotes: 1

Related Questions