0

In this example below, I want to reset the input field back to an empty string after clicking submit: https://codesandbox.io/s/todo-app-object-vk99c

Form.js:

class Form extends Component {
  state = {
    todo: { name: "" }
    // inputValue: ""
  };

  onChange = (e) => {
    const newTodo = {
      id: Math.random() * 10000,
      name: e.target.value,
      completed: false
    };

    this.setState({
      todo: newTodo
    });
  };

  onSubmit = async (e) => {
    e.preventDefault();
    this.props.addTodo(this.state.todo);
    console.log(this.state.todo, "this.state.todo 1");
    await this.setState({
      todo: {}
    });
    console.log(this.state.todo, "this.state.todo 2");
  };

  render() {
    return (
      <form className="Form">
        <input
          type="text"
          className="input"
          onChange={this.onChange}
          value={this.state.todo.name}
        />
        <button className="submit" onClick={this.onSubmit}>
          Submit
        </button>
        {this.state.todo.name}
      </form>
    );
  }
}

export default Form;

App.js:

 addTodo = (newTodo) => {
    const newState = [...this.state.todos, newTodo];
    this.setState({
      todos: newState
    });
  };

My questions are:

  1. I want to update the name string to an empty string, and it seems like it works if it's not part of the input field. Why is this happening? Before I click submit: https://i.stack.imgur.com/0kuEo.jpg , After I click submit: https://i.stack.imgur.com/TaI13.jpg (Notice how the text next to the submit button is reseted to an empty string, so why does React update the state in 1 place but not the other?)

  2. I got the following warning:

Warning: A component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined to a defined value, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: https://reactjs.org/link/controlled-components
    at input
    at form
    at Form (https://vk99c.csb.app/src/Components/Form/Form.js:50:34)
    at div
    at App (https://vk99c.csb.app/src/App.js:51:34)

Which I think is rather vague. I know the Form (which is a controlled input in React) is the problem, but don't understand what the warning is telling me, and how to fix it.

Update: I believe this code has something to do with it:

onSubmit = async (e) => {
    e.preventDefault();
    this.props.addTodo(this.state.todo);
    console.log(this.state.todo, "this.state.todo 1");
    await this.setState({
      todo: {
        name: {}
      }
    });
    console.log(this.state.todo, "this.state.todo 2");
  };

When I changed {} to "", it works, and the warning is gone, but still, I don't understand why it will work at one place but not the other, and what the warning was saying.

EDIT: I got suggested this answer React - changing an uncontrolled input , but it is not my situation, as my initial state wasn't an empty object in Form.js

todo: { name: "" }
  • 1
    In your codesanbox snippet you do `this.setState({todo: {}})`, since this doesn't have a `name` key, using `this.state.todo.name` as a value doesn't correspond to a state value, as the `name` key does not exist on the `todo` object. – Nick Parsons Mar 14 '21 at 02:44
  • I did notice that as well. However, why was it that the string next to the `submit` button still being updated (reset to empty string) whereas the string in the input field was not, because they were controlled by the same `onSubmit` function? – Heymanyoulookkindacool Mar 14 '21 at 02:46
  • 1
    That's because your `onSubmit` will set the state to `{todo: {}}`, as a result `this.state.todo.name` will be `undefined`. React doesn't display `undefined` values, so it gets hidden in the output. Since your `value` for the input field is now not set to a state value you'll get the error about it being uncontrolled. You can see this by checking for undefined and manually showing a string value: `{this.state.todo.name === undefined ? "undefined" : this.state.todo.name}`. this will show `"undefined"` when `this.state.todo.name` is `undefined` – Nick Parsons Mar 14 '21 at 02:50
  • I think I'm beginning to understand. So in the case of the text next to the `submit` button, are you saying it's not that the string is set to empty, but because it's `undefined`, there's nothing displayed there? If that's the case, then why does the string in the input field stays the same? I'm talking about these 2 before and after cases after clicking submit here: 1) https://imgur.com/hONqktR 2) https://imgur.com/HwL6FZT – Heymanyoulookkindacool Mar 14 '21 at 02:55
  • 1
    Yes, that's right, it's because it's `undefined` that it's not being displayed, not because it's an empty string. The value of the input box does not change though, since setting the `value` to `undefined` just makes the input box "uncontrolled", it doesn't change the value within the textbox/input - more [here](https://reactjs.org/docs/forms.html#controlled-input-null-value) – Nick Parsons Mar 14 '21 at 03:00
  • Thank you! A question on `uncontrolled` input box: Does `uncontrolled` here mean that we lost controlled of the input field when we let it take on an `undefined` value? In practice, what does that mean to the behavior of the form? – Heymanyoulookkindacool Mar 14 '21 at 03:19
  • 1
    The way I think about it is if an input is controlled, then there is some state that is driving the value of that input. When the value is `undefined`, then there is no state driving its value anymore, so it's not being controlled by your applications state (ie: it's uncontrolled). In practice, this could lead to inconsistency between your react state and what's being entered into the input textbox (ie the DOM) - more info in the first paragraph of [this article](https://reactjs.org/docs/uncontrolled-components.html). – Nick Parsons Mar 14 '21 at 03:28

0 Answers0