8

I am trying to get rid off this error message, but still unsuccessfully.

Warning: A component is changing an uncontrolled input of type text to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component.

There's also link to the Facebook page, but I am still not sure how to figure it out.

class EditItem extends Component {
    constructor(props) {
        super(props);
        this.state = {items: ''};

        this.addItemService = new ItemService();
        this.handleChange = this.handleChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
  }

  componentDidMount(){
    axios.get('http://localhost:3005/items/edit/'+this.props.match.params.id)
    .then(response => {
      this.setState({ items: response.data });
    })
    .catch(function (error) {
      console.log(error);
    })
  }

  handleChange = (e) => {
    let items = Object.assign({}, this.state.items);    //creating copy of object
    items.item = e.target.value;                        //updating value
    this.setState({items});
  }

  handleSubmit(event) {
    event.preventDefault(); // not sure why this
    this.addItemService.updateData(this.state.items.item, this.props.match.params.id); // service for updating the data
    this.props.history.push('/index'); // redirect
  }

  render() {
    return (
          <div className="container">
            <form onSubmit={this.handleSubmit}>
              <label>
                Edit Item:
                <input type="text" value={this.state.items.item} className="form-control" onChange={this.handleChange}/>
              </label><br/>
              <input type="submit" value="Update" className="btn btn-primary"/>
            </form>
        </div>
    );
  }
}

In the input seems to be always a not-null value, how do I fix this?

1
  • this.state.items.item is undefined until the first onChange event. You could change your initial state to this.state = {items: { item: '' } }; to get rid of the warning. Commented Jul 18, 2018 at 16:33

3 Answers 3

23

In the state items is defined as a string, and hence when you assign the value to text input like

<input type="text" value={this.state.items.item} className="form-control" onChange={this.handleChange}/>

You are essentially writing

<input type="text" value={undefined} className="form-control" onChange={this.handleChange}/>

for the initial render, and once the result of API call is available and items state changes to an object that contains item key, you are passing a value to input and hence converting it from uncontrolled to controlled, which is what the warning is about. In order to avoid the warning, you would simply initilise your state like

this.state = {items: { items: '' }};

or use input like

<input type="text" value={this.state.items.item || ''} className="form-control" onChange={this.handleChange}/>
Sign up to request clarification or add additional context in comments.

2 Comments

After scouring for an hour or so of similar threads, this was the only comment that was incredibly on-point! Thanks, I finally get it!
I've encountered this problem because I'm using a functional component with value and onChange. Changing <TextField value={question} onChange={e => setQuestion(e.target.value)} label="Question" /> to <TextField value={question || ''} onChange={e => setQuestion(e.target.value)} label="Question" /> . By adding || '' on the value removes the error, what sorcery is this?
0

This type of warning mainly occurs in React when you try to set the undefined value to any of the input types. You can use a conditional operator to check whether the state value is undefined or not, if it is undefined set it to a null value.


<input type="text" value={this.state.items.item !== undefined ? this.state.items.item :  ''} className="form-control" onChange={this.handleChange}/>


Comments

-1

🚨 If you’re getting undefined for your item key, the issue happens because it doesn’t have an initial value. When a property isn’t defined, it automatically becomes undefined. To fix this, just set an initial value for it in your component’s state. Here’s how you can update your code:

// -- Updated Code -- //
constructor(props) {
    super(props);
    this.state = {
      items: {
        item: '', // Add a default value for 'item'
      },
    };

    this.addItemService = new ItemService();
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
}
// ... Rest of your code

Another thing I noticed is that you’re updating properties manually. There’s a simpler and more efficient way to handle this dynamically, especially for forms with multiple inputs. Here’s how you can make your code shorter and cleaner:

  1. Add the name property to your input field
    This allows you to dynamically update state based on the input field’s name. For example:

    <input 
      type="text" 
      value={this.state.items.item} 
      className="form-control" 
      onChange={this.handleChange} 
      name="item" 
    />
    
  2. Update the handleChange function
    Use the input’s name to automatically update the corresponding state key:

    handleChange = (e) => {
      this.setState({
        items: {
          ...this.state.items,
          [e.target.name]: e.target.value, // Dynamically update the key based on the input name
        },
      });
    }
    

The Result

If you put these updates together, your input will work properly, and your form will also become easier to manage and scale in the future. This method has been reliable for years, so give it a try and disregard the negative rep lol.

For more details, you can check out this other implementation where I used this.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.